diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 103166ff1..f1d0ef977 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -13,6 +13,7 @@ import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivit import com.simibubi.create.content.schematics.ClientSchematicLoader; import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.content.schematics.client.SchematicHandler; +import com.simibubi.create.events.ClientEvents; import com.simibubi.create.foundation.ResourceReloadHandler; import com.simibubi.create.foundation.block.render.CustomBlockModels; import com.simibubi.create.foundation.block.render.SpriteShifter; @@ -80,6 +81,7 @@ public class CreateClient { modEventBus.addListener(CreateClient::onModelRegistry); modEventBus.addListener(CreateClient::onTextureStitch); modEventBus.addListener(AllParticleTypes::registerFactories); + modEventBus.addListener(ClientEvents::loadCompleted); Backend.init(); OptifineHandler.init(); @@ -110,11 +112,14 @@ public class CreateClient { PonderIndex.registerTags(); UIRenderHelper.init(); + UIRenderHelper.enableStencil(); IResourceManager resourceManager = Minecraft.getInstance() .getResourceManager(); if (resourceManager instanceof IReloadableResourceManager) ((IReloadableResourceManager) resourceManager).addReloadListener(new ResourceReloadHandler()); + + } public static void onTextureStitch(TextureStitchEvent.Pre event) { diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BlockzapperUpgradeCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BlockzapperUpgradeCategory.java index 581ebc9cd..427f83df2 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/BlockzapperUpgradeCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/BlockzapperUpgradeCategory.java @@ -88,7 +88,7 @@ public class BlockzapperUpgradeCategory extends CreateRecipeCategoryat(90, 0) .scale(3.5) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java index 1c2d29343..99a5cbaf0 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java @@ -73,7 +73,7 @@ public class PolishingCategory extends CreateRecipeCategoryat(getBackground().getWidth() / 2 - 16, 0, 0) .scale(2) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java index 157ff3ecc..fb073cbc2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftScreen.java @@ -153,7 +153,7 @@ public class SequencedGearshiftScreen extends AbstractSimiScreen { 0xffffff); GuiGameElement.of(renderedItem) - .at(guiLeft + background.width + 10, guiTop + 100, -150) + .at(guiLeft + background.width + 10, guiTop + 100, -150) .scale(5) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java index 3c95f62ec..288de4b54 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/symmetry/SymmetryWandScreen.java @@ -123,7 +123,7 @@ public class SymmetryWandScreen extends AbstractSimiScreen { renderBlock(matrixStack); GuiGameElement.of(wand) - .at(guiLeft + 190, guiTop + 420, -150) + .at(guiLeft + 190, guiTop + 420, -150) .scale(4) .rotate(-70, 20, 20) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java index bb5a6f3c7..ff58a8bf1 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperScreen.java @@ -133,7 +133,7 @@ public class ZapperScreen extends AbstractSimiScreen { protected void renderZapper(MatrixStack matrixStack) { GuiGameElement.of(zapper) - .at((this.width - this.sWidth) / 2 + 200, this.height / 2 - this.sHeight / 4 + 25, -150) + .at((this.width - this.sWidth) / 2 + 200, this.height / 2 - this.sHeight / 4 + 25, -150) .scale(4) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java index 3d10ccc62..d8e532662 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateScreen.java @@ -97,7 +97,7 @@ public class AdjustableCrateScreen extends AbstractSimiContainerScreenat(guiLeft + ADJUSTABLE_CRATE.width + 110, guiTop + 70, -150) .scale(5) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java index 84f468933..acca08977 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchScreen.java @@ -126,7 +126,7 @@ public class StockpileSwitchScreen extends AbstractSimiScreen { matrixStack.push(); GuiGameElement.of(renderedItem) - .at(guiLeft + STOCKSWITCH.width + 15, guiTop + 40, -250) + .at(guiLeft + STOCKSWITCH.width + 15, guiTop + 40, -250) .scale(5) .render(matrixStack); matrixStack.pop(); diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java index ab37bf0bd..79cefef17 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java @@ -69,7 +69,7 @@ public abstract class AbstractFilterScreen ex textRenderer.draw(ms, I18n.format(container.filterItem.getTranslationKey()), x + 15, y + 3, 0xdedede); GuiGameElement.of(container.filterItem) - .at(x + background.width, guiTop + background.height - 60) + .at(x + background.width, guiTop + background.height - 60) .scale(5) .render(ms); diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java index cd21994a5..93b98c4b7 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicTableScreen.java @@ -122,7 +122,7 @@ public class SchematicTableScreen extends AbstractSimiContainerScreenat(mainLeft + 217, mainTop + 50, -150) .scale(3) .render(matrixStack); diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java index 6d08924a9..f1e5a3032 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java @@ -262,7 +262,7 @@ public class SchematicannonScreen extends AbstractSimiContainerScreenat(guiLeft + 230, guiTop + 110, -200) .scale(5) .render(matrixStack); @@ -274,7 +274,7 @@ public class SchematicannonScreen extends AbstractSimiContainerScreenat(guiLeft + 150, guiTop + 46, 100) .scale(1) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java index aec2fc8c8..b775572c0 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicEditScreen.java @@ -152,7 +152,7 @@ public class SchematicEditScreen extends AbstractSimiScreen { x + 93 - textRenderer.getStringWidth(handler.getCurrentSchematicName()) / 2, y + 3, 0xffffff); GuiGameElement.of(AllItems.SCHEMATIC.asStack()) - .at(guiLeft + 200, guiTop + 82, 0) + .at(guiLeft + 200, guiTop + 82, 0) .scale(3) .render(matrixStack); } diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 67a92c975..29b561e56 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -30,6 +30,7 @@ import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperR import com.simibubi.create.content.logistics.block.depot.EjectorTargetHandler; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.config.ui.BaseConfigScreen; import com.simibubi.create.foundation.item.ItemDescription; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; @@ -78,7 +79,11 @@ import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; @EventBusSubscriber(value = Dist.CLIENT) public class ClientEvents { @@ -310,4 +315,9 @@ public class ClientEvents { } } + public static void loadCompleted(FMLLoadCompleteEvent event) { + ModContainer createContainer = ModList.get().getModContainerById("create").orElseThrow(() -> new IllegalStateException("Create Mod Container missing after loadCompleted")); + createContainer.registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, () -> (mc, previousScreen) -> new BaseConfigScreen(previousScreen)); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java index bf6883875..81b4a5f5a 100644 --- a/src/main/java/com/simibubi/create/foundation/command/AllCommands.java +++ b/src/main/java/com/simibubi/create/foundation/command/AllCommands.java @@ -21,20 +21,22 @@ public class AllCommands { LiteralCommandNode util = buildUtilityCommands(); LiteralCommandNode createRoot = dispatcher.register(Commands.literal("create") - .requires(cs -> cs.hasPermissionLevel(0)) - // general purpose - .then(new ToggleExperimentalRenderingCommand().register()) - .then(new ToggleDebugCommand().register()) - .then(FabulousWarningCommand.register()) - .then(OverlayConfigCommand.register()) - .then(FixLightingCommand.register()) - .then(HighlightCommand.register()) - .then(CouplingCommand.register()) - .then(CloneCommand.register()) - .then(PonderCommand.register()) + .requires(cs -> cs.hasPermissionLevel(0)) + // general purpose + .then(new ToggleExperimentalRenderingCommand().register()) + .then(new ToggleDebugCommand().register()) + .then(FabulousWarningCommand.register()) + .then(OverlayConfigCommand.register()) + .then(FixLightingCommand.register()) + .then(HighlightCommand.register()) + .then(CouplingCommand.register()) + .then(ConfigCommand.register()) + .then(PonderCommand.register()) + .then(CloneCommand.register()) - // utility - .then(util)); + // utility + .then(util) + ); createRoot.addChild(buildRedirect("u", util)); @@ -50,12 +52,12 @@ public class AllCommands { private static LiteralCommandNode buildUtilityCommands() { return Commands.literal("util") - .then(ReplaceInCommandBlocksCommand.register()) - .then(ClearBufferCacheCommand.register()) - .then(ChunkUtilCommand.register()) - .then(FlySpeedCommand.register()) - // .then(KillTPSCommand.register()) - .build(); + .then(ReplaceInCommandBlocksCommand.register()) + .then(ClearBufferCacheCommand.register()) + .then(ChunkUtilCommand.register()) + .then(FlySpeedCommand.register()) + //.then(KillTPSCommand.register()) + .build(); } @@ -72,15 +74,15 @@ public class AllCommands { * * @return the built node */ - public static LiteralCommandNode buildRedirect(final String alias, - final LiteralCommandNode destination) { + public static LiteralCommandNode buildRedirect(final String alias, final LiteralCommandNode destination) { // Redirects only work for nodes with children, but break the top argument-less command. // Manually adding the root command after setting the redirect doesn't fix it. // See https://github.com/Mojang/brigadier/issues/46). Manually clone the node instead. - LiteralArgumentBuilder builder = LiteralArgumentBuilder.literal(alias) - .requires(destination.getRequirement()) - .forward(destination.getRedirect(), destination.getRedirectModifier(), destination.isFork()) - .executes(destination.getCommand()); + LiteralArgumentBuilder builder = LiteralArgumentBuilder + .literal(alias) + .requires(destination.getRequirement()) + .forward(destination.getRedirect(), destination.getRedirectModifier(), destination.isFork()) + .executes(destination.getCommand()); for (CommandNode child : destination.getChildren()) { builder.then(child); } diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigCommand.java b/src/main/java/com/simibubi/create/foundation/command/ConfigCommand.java new file mode 100644 index 000000000..24a45110a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/command/ConfigCommand.java @@ -0,0 +1,27 @@ +package com.simibubi.create.foundation.command; + +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraftforge.fml.network.PacketDistributor; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.simibubi.create.foundation.networking.AllPackets; + +public class ConfigCommand { + + public static ArgumentBuilder register() { + return Commands.literal("config") + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource().asPlayer(); + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.configScreen.name(), "") + ); + + return Command.SINGLE_SUCCESS; + }); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java b/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java index c2f9c5eb1..2c03d40b0 100644 --- a/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/FabulousWarningCommand.java @@ -13,16 +13,18 @@ public class FabulousWarningCommand { public static ArgumentBuilder register() { return Commands.literal("dismissFabulousWarning") - .requires(AllCommands.sourceIsPlayer) - .executes(ctx -> { - ServerPlayerEntity player = ctx.getSource() - .asPlayer(); + .requires(AllCommands.sourceIsPlayer) + .executes(ctx -> { + ServerPlayerEntity player = ctx.getSource() + .asPlayer(); - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.fabulousWarning.name(), "")); + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.fabulousWarning.name(), "") + ); - return Command.SINGLE_SUCCESS; - }); + return Command.SINGLE_SUCCESS; + }); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java b/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java index 7a128bced..4557c07ad 100644 --- a/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/FixLightingCommand.java @@ -17,7 +17,7 @@ public class FixLightingCommand { .executes(ctx -> { AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource() .getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.fixLighting.name(), String.valueOf(true))); + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.fixLighting.name(), String.valueOf(true))); ctx.getSource() .sendFeedback( diff --git a/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java b/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java index bb17a4b02..034746d58 100644 --- a/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/OverlayConfigCommand.java @@ -15,35 +15,32 @@ public class OverlayConfigCommand { public static ArgumentBuilder register() { return Commands.literal("overlay") - .requires(cs -> cs.hasPermissionLevel(0)) - .then(Commands.literal("reset") - .executes(ctx -> { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> ConfigureConfigPacket.Actions.overlayReset.performAction("")); + .requires(cs -> cs.hasPermissionLevel(0)) + .then(Commands.literal("reset") + .executes(ctx -> { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SConfigureConfigPacket.Actions.overlayReset.performAction("")); - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, - () -> () -> AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource() - .getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.overlayReset.name(), ""))); + DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.overlayReset.name(), ""))); ctx.getSource() .sendFeedback(new StringTextComponent("reset overlay offset"), true); - return 1; - })) - .executes(ctx -> { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, - () -> () -> ConfigureConfigPacket.Actions.overlayScreen.performAction("")); + return 1; + }) + ) + .executes(ctx -> { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SConfigureConfigPacket.Actions.overlayScreen.performAction("")); - DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, - () -> () -> AllPackets.channel.send( - PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource() - .getEntity()), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.overlayScreen.name(), ""))); + DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () -> + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) ctx.getSource().getEntity()), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.overlayScreen.name(), ""))); - ctx.getSource() - .sendFeedback(new StringTextComponent("window opened"), true); + ctx.getSource() + .sendFeedback(new StringTextComponent("window opened"), true); return 1; }); diff --git a/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java b/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java index 8fe17795e..70d353a64 100644 --- a/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/PonderCommand.java @@ -21,26 +21,20 @@ import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.fml.network.PacketDistributor; public class PonderCommand { - public static final SuggestionProvider ITEM_PONDERS = SuggestionProviders.register( - new ResourceLocation("all_ponders"), - (iSuggestionProviderCommandContext, builder) -> ISuggestionProvider.func_212476_a(PonderRegistry.all.keySet() - .stream(), builder)); + public static final SuggestionProvider ITEM_PONDERS = SuggestionProviders.register(new ResourceLocation("all_ponders"), (iSuggestionProviderCommandContext, builder) -> ISuggestionProvider.func_212476_a(PonderRegistry.all.keySet().stream(), builder)); static ArgumentBuilder register() { return Commands.literal("ponder") - .requires(cs -> cs.hasPermissionLevel(0)) - .executes(ctx -> openScene("index", ctx.getSource() - .asPlayer())) - .then(Commands.argument("scene", ResourceLocationArgument.resourceLocation()) - .suggests(ITEM_PONDERS) - .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene") - .toString(), - ctx.getSource() - .asPlayer())) - .then(Commands.argument("targets", EntityArgument.players()) - .requires(cs -> cs.hasPermissionLevel(2)) - .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene") - .toString(), EntityArgument.getPlayers(ctx, "targets"))))); + .requires(cs -> cs.hasPermissionLevel(0)) + .executes(ctx -> openScene("index", ctx.getSource().asPlayer())) + .then(Commands.argument("scene", ResourceLocationArgument.resourceLocation()) + .suggests(ITEM_PONDERS) + .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene").toString(), ctx.getSource().asPlayer())) + .then(Commands.argument("targets", EntityArgument.players()) + .requires(cs -> cs.hasPermissionLevel(2)) + .executes(ctx -> openScene(ResourceLocationArgument.getResourceLocation(ctx, "scene").toString(), EntityArgument.getPlayers(ctx, "targets"))) + ) + ); } @@ -53,8 +47,9 @@ public class PonderCommand { if (player instanceof FakePlayer) continue; - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.openPonder.name(), sceneId)); + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.openPonder.name(), sceneId)); } return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java b/src/main/java/com/simibubi/create/foundation/command/SConfigureConfigPacket.java similarity index 93% rename from src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java rename to src/main/java/com/simibubi/create/foundation/command/SConfigureConfigPacket.java index 28339f5c0..c1dcd3105 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ConfigureConfigPacket.java +++ b/src/main/java/com/simibubi/create/foundation/command/SConfigureConfigPacket.java @@ -8,6 +8,7 @@ import org.apache.logging.log4j.LogManager; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.config.ui.BaseConfigScreen; import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.ponder.PonderRegistry; @@ -31,17 +32,17 @@ import net.minecraftforge.common.ForgeConfig; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.NetworkEvent; -public class ConfigureConfigPacket extends SimplePacketBase { +public class SConfigureConfigPacket extends SimplePacketBase { private final String option; private final String value; - public ConfigureConfigPacket(String option, String value) { + public SConfigureConfigPacket(String option, String value) { this.option = option; this.value = value; } - public ConfigureConfigPacket(PacketBuffer buffer) { + public SConfigureConfigPacket(PacketBuffer buffer) { this.option = buffer.readString(32767); this.value = buffer.readString(32767); } @@ -69,7 +70,8 @@ public class ConfigureConfigPacket extends SimplePacketBase { .setPacketHandled(true); } - enum Actions { + public enum Actions { + configScreen(() -> Actions::configScreen), rainbowDebug(() -> Actions::rainbowDebug), overlayScreen(() -> Actions::overlayScreen), fixLighting(() -> Actions::experimentalLighting), @@ -91,6 +93,11 @@ public class ConfigureConfigPacket extends SimplePacketBase { .accept(value); } + @OnlyIn(Dist.CLIENT) + private static void configScreen(String value) { + ScreenOpener.open(new BaseConfigScreen(null)); + } + @OnlyIn(Dist.CLIENT) private static void rainbowDebug(String value) { ClientPlayerEntity player = Minecraft.getInstance().player; diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java index 59673f15e..f5b73ecbb 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleDebugCommand.java @@ -13,7 +13,9 @@ public class ToggleDebugCommand extends ConfigureConfigCommand { @Override protected void sendPacket(ServerPlayerEntity player, String option) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.rainbowDebug.name(), option)); + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.rainbowDebug.name(), option) + ); } } diff --git a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java index 4c01fa62a..19c761f74 100644 --- a/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java +++ b/src/main/java/com/simibubi/create/foundation/command/ToggleExperimentalRenderingCommand.java @@ -13,7 +13,9 @@ public class ToggleExperimentalRenderingCommand extends ConfigureConfigCommand { @Override protected void sendPacket(ServerPlayerEntity player, String option) { - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), - new ConfigureConfigPacket(ConfigureConfigPacket.Actions.experimentalRendering.name(), option)); + AllPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureConfigPacket(SConfigureConfigPacket.Actions.experimentalRendering.name(), option) + ); } } diff --git a/src/main/java/com/simibubi/create/foundation/config/ConfigBase.java b/src/main/java/com/simibubi/create/foundation/config/ConfigBase.java index 213f8ff51..0dadcfc41 100644 --- a/src/main/java/com/simibubi/create/foundation/config/ConfigBase.java +++ b/src/main/java/com/simibubi/create/foundation/config/ConfigBase.java @@ -107,8 +107,7 @@ public abstract class ConfigBase { if (comment.length > 0) { String[] comments = new String[comment.length + 1]; comments[0] = ""; - for (int i = 0; i < comment.length; i++) - comments[i + 1] = comment[i]; + System.arraycopy(comment, 0, comments, 1, comment.length); builder.comment(comments); } else builder.comment(""); diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java new file mode 100644 index 000000000..915abcb38 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/BaseConfigScreen.java @@ -0,0 +1,59 @@ +package com.simibubi.create.foundation.config.ui; + +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.TextStencilElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.config.ModConfig; + +public class BaseConfigScreen extends ConfigScreen { + + BoxWidget clientConfigWidget; + BoxWidget commonConfigWidget; + BoxWidget serverConfigWidget; + + public BaseConfigScreen(Screen parent) { + super(parent); + } + + @Override + protected void init() { + widgets.clear(); + super.init(); + + TextStencilElement text = new TextStencilElement(client.fontRenderer, new StringTextComponent("Client Settings").formatted(TextFormatting.BOLD)).centered(true, true); + widgets.add(clientConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15 - 30, 200, 16) + .showingElement(text) + .withCallback(() -> ScreenOpener.open(new SubMenuConfigScreen(this, ModConfig.Type.CLIENT, AllConfigs.CLIENT.specification))) + ); + text.withElementRenderer(BoxWidget.gradientFactory.apply(clientConfigWidget)); + + TextStencilElement text2 = new TextStencilElement(client.fontRenderer, new StringTextComponent("World Generation Settings").formatted(TextFormatting.BOLD)).centered(true, true); + widgets.add(commonConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15, 200, 16) + .showingElement(text2) + .withCallback(() -> ScreenOpener.open(new SubMenuConfigScreen(this, ModConfig.Type.COMMON, AllConfigs.COMMON.specification))) + ); + text2.withElementRenderer(BoxWidget.gradientFactory.apply(commonConfigWidget)); + + TextStencilElement text3 = new TextStencilElement(client.fontRenderer, new StringTextComponent("Gameplay Settings").formatted(TextFormatting.BOLD)).centered(true, true); + widgets.add(serverConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15 + 30, 200, 16) + .showingElement(text3) + ); + + if (Minecraft.getInstance().world != null) { + serverConfigWidget.withCallback(() -> ScreenOpener.open(new SubMenuConfigScreen(this, ModConfig.Type.SERVER, AllConfigs.SERVER.specification))); + text3.withElementRenderer(BoxWidget.gradientFactory.apply(serverConfigWidget)); + } else { + serverConfigWidget.active = false; + serverConfigWidget.updateColorsFromState(); + text3.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.i(Theme.Key.BUTTON_DISABLE, true), Theme.i(Theme.Key.BUTTON_DISABLE, false) | 0x40_000000)); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/CConfigureConfigPacket.java b/src/main/java/com/simibubi/create/foundation/config/ui/CConfigureConfigPacket.java new file mode 100644 index 000000000..c1a475d29 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/CConfigureConfigPacket.java @@ -0,0 +1,83 @@ +package com.simibubi.create.foundation.config.ui; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.command.SConfigureConfigPacket; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.fml.network.PacketDistributor; + +public class CConfigureConfigPacket extends SimplePacketBase { + + private String path; + private String value; + + public CConfigureConfigPacket(String path, T value) { + this.path = path; + this.value = serialize(value); + } + + public CConfigureConfigPacket(PacketBuffer buffer) { + this.path = buffer.readString(32767); + this.value = buffer.readString(32767); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeString(path); + buffer.writeString(value); + } + + @Override + public void handle(Supplier context) { + ServerPlayerEntity sender = context.get().getSender(); + if (sender == null || !sender.hasPermissionLevel(2)) + return; + + ForgeConfigSpec.ValueSpec valueSpec = AllConfigs.SERVER.specification.getRaw(path); + ForgeConfigSpec.ConfigValue configValue = AllConfigs.SERVER.specification.getValues().get(path); + + T v = (T) deserialize(configValue.get(), value); + if (!valueSpec.test(v)) + return; + + configValue.set(v); + + } + + public String serialize(T value) { + if (value instanceof Boolean) + return Boolean.toString((Boolean) value); + if (value instanceof Enum) + return ((Enum) value).name(); + if (value instanceof Integer) + return Integer.toString((Integer) value); + if (value instanceof Float) + return Float.toString((Float) value); + if (value instanceof Double) + return Double.toString((Double) value); + + throw new IllegalArgumentException("unknown type " + value + ": " + value.getClass().getSimpleName()); + } + + public Object deserialize(Object type, String sValue) { + if (type instanceof Boolean) + return Boolean.parseBoolean(sValue); + if (type instanceof Enum) + return Enum.valueOf(((Enum) type).getClass(), sValue); + if (type instanceof Integer) + return Integer.parseInt(sValue); + if (type instanceof Float) + return Float.parseFloat(sValue); + if (type instanceof Double) + return Double.parseDouble(sValue); + + throw new IllegalArgumentException("unknown type " + type + ": " + type.getClass().getSimpleName()); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java new file mode 100644 index 000000000..fdcf71eff --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreen.java @@ -0,0 +1,123 @@ +package com.simibubi.create.foundation.config.ui; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.StringUtils; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; +import com.simibubi.create.foundation.gui.AbstractSimiScreen; +import com.simibubi.create.foundation.gui.GuiGameElement; +import com.simibubi.create.foundation.gui.StencilElement; +import com.simibubi.create.foundation.utility.animation.Force; +import com.simibubi.create.foundation.utility.animation.PhysicalFloat; + +import net.minecraft.block.BlockState; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.Direction; + +public abstract class ConfigScreen extends AbstractSimiScreen { + + /* + * + * zelo's list for configUI + * TODO + * + * replace java's awt color with something mutable + * + * FIXME + * + * tooltips are hidden underneath the scrollbar, if the bar is near the middle + * framebuffer blending is incorrect -> wait for jozu's changes to merge + * + * */ + + public static final PhysicalFloat cogSpin = PhysicalFloat.create().withDrag(0.3).addForce(new Force.Static(.2f)); + public static final BlockState cogwheelState = AllBlocks.LARGE_COGWHEEL.getDefaultState().with(CogWheelBlock.AXIS, Direction.Axis.Y); + public static final Map changes = new HashMap<>(); + protected final Screen parent; + + public ConfigScreen(Screen parent) { + this.parent = parent; + } + + @Override + public void tick() { + super.tick(); + cogSpin.tick(); + } + + @Override + public void renderBackground(@Nonnull MatrixStack ms) { + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.GuiScreenEvent.BackgroundDrawnEvent(this, ms)); + } + + @Override + protected void renderWindowBackground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + //RenderSystem.disableDepthTest(); + if (this.client != null && this.client.world != null) { + fill(ms, 0, 0, this.width, this.height, 0xb0_282c34); + } else { + fill(ms, 0, 0, this.width, this.height, 0xff_282c34); + } + + new StencilElement() { + @Override + protected void renderStencil(MatrixStack ms) { + renderCog(ms, partialTicks); + } + + @Override + protected void renderElement(MatrixStack ms) { + fill(ms, -200, -200, 200, 200, 0x60_000000); + } + }.at(width * 0.5f, height * 0.5f, 0).render(ms); + + super.renderWindowBackground(ms, mouseX, mouseY, partialTicks); + + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + int x = (int) (width * 0.5f); + int y = (int) (height * 0.5f); + //this.drawHorizontalLine(ms, x-25, x+25, y, 0xff_807060); + //this.drawVerticalLine(ms, x, y-25, y+25, 0xff_90a0b0); + + //this.testStencil.render(ms); + + //UIRenderHelper.streak(ms, 0, mouseX, mouseY, 16, 50, 0xaa_1e1e1e); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + cogSpin.bump(3, -delta * 5); + + return super.mouseScrolled(mouseX, mouseY, delta); + } + + public static String toHumanReadable(String key) { + String s = key.replaceAll("_", " "); + s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" ")); + s = s.replaceAll("\\s\\s+", " "); + return s; + } + + protected void renderCog(MatrixStack ms, float partialTicks) { + ms.push(); + + ms.translate(-100, 100, -100); + ms.scale(200, 200, .1f); + GuiGameElement.of(cogwheelState) + .rotateBlock(22.5, cogSpin.getValue(partialTicks), 22.5) + .render(ms); + + ms.pop(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java new file mode 100644 index 000000000..71b6680ff --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigScreenList.java @@ -0,0 +1,180 @@ +package com.simibubi.create.foundation.config.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.config.ui.entries.NumberEntry; +import com.simibubi.create.foundation.gui.TextStencilElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; + +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.IGuiEventListener; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.gui.widget.list.ExtendedList; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.fml.client.gui.GuiUtils; + +public class ConfigScreenList extends ExtendedList { + + public static TextFieldWidget currentText; + + public boolean isForServer = false; + + public ConfigScreenList(Minecraft client, int width, int height, int top, int bottom, int elementHeight) { + super(client, width, height, top, bottom, elementHeight); + func_244605_b(false); + func_244606_c(false); + setRenderSelection(false); + currentText = null; + headerHeight = 3; + } + + @Override + public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + //render tmp background + //fill(ms, left, top, left + width, top + height, 0x10_000000); + + UIRenderHelper.angledGradient(ms, 90, left + width / 2, top, width, 5, 0x60_000000, 0x0); + UIRenderHelper.angledGradient(ms, -90, left + width / 2, bottom, width, 5, 0x60_000000, 0x0); + UIRenderHelper.angledGradient(ms, 0, left, top + height / 2, height, 5, 0x60_000000, 0x0); + UIRenderHelper.angledGradient(ms, 180, right, top + height / 2, height, 5, 0x60_000000, 0x0); + + super.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + protected void renderList(MatrixStack p_238478_1_, int p_238478_2_, int p_238478_3_, int p_238478_4_, int p_238478_5_, float p_238478_6_) { + MainWindow window = Minecraft.getInstance().getWindow(); + double d0 = window.getGuiScaleFactor(); + RenderSystem.enableScissor((int) (this.left * d0), (int) (window.getFramebufferHeight() - (this.bottom * d0)), (int) (this.width * d0), (int) (this.height * d0)); + super.renderList(p_238478_1_, p_238478_2_, p_238478_3_, p_238478_4_, p_238478_5_, p_238478_6_); + RenderSystem.disableScissor(); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + children().stream().filter(e -> e instanceof NumberEntry).forEach(e -> e.mouseClicked(x, y, button)); + + return super.mouseClicked(x, y, button); + } + + @Override + public int getRowWidth() { + return width - 16; + } + + @Override + protected int getScrollbarPositionX() { + return left + this.width - 6; + } + + public void tick() { + //children().forEach(Entry::tick); + for(int i = 0; i < getItemCount(); ++i) { + int top = this.getRowTop(i); + int bot = top + itemHeight; + if (bot >= this.top && top <= this.bottom) + this.getEntry(i).tick(); + } + + } + + public void bumpCog(float force) { + ConfigScreen.cogSpin.bump(3, force); + } + + public static abstract class Entry extends ExtendedList.AbstractListEntry { + protected List listeners; + + protected Entry() { + listeners = new ArrayList<>(); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + return getGuiListeners().stream().anyMatch(l -> l.mouseClicked(x, y, button)); + } + + @Override + public boolean keyPressed(int code, int keyPressed_2_, int keyPressed_3_) { + return getGuiListeners().stream().anyMatch(l -> l.keyPressed(code, keyPressed_2_, keyPressed_3_)); + } + + @Override + public boolean charTyped(char ch, int code) { + return getGuiListeners().stream().anyMatch(l -> l.charTyped(ch, code)); + } + + public void tick() {} + + public List getGuiListeners() { + return listeners; + } + + protected void setEditable(boolean b) {} + } + + public static class LabeledEntry extends Entry { + + protected static final float labelWidthMult = 0.4f; + + protected TextStencilElement label; + protected List labelTooltip; + protected String unit = null; + + public LabeledEntry(String label) { + this.label = new TextStencilElement(Minecraft.getInstance().fontRenderer, label); + this.label.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.p(Theme.Key.TEXT_ACCENT_STRONG))); + labelTooltip = new ArrayList<>(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { + UIRenderHelper.streak(ms, 0, x, y + height / 2, height - 6, width, 0xdd_000000); + IFormattableTextComponent component = label.getComponent(); + FontRenderer font = Minecraft.getInstance().fontRenderer; + if (font.getWidth(component) > getLabelWidth(width) - 10) { + label.withText(font.trimToWidth(component, getLabelWidth(width) - 15).getString() + "..."); + } + if (unit != null) { + int unitWidth = font.getStringWidth(unit); + font.draw(ms, unit, x + getLabelWidth(width) - unitWidth - 5, y + height / 2 + 2, Theme.i(Theme.Key.TEXT_DARKER)); + label.at(x + 10, y + height / 2 - 10, 0).render(ms); + } else { + label.at(x + 10, y + height / 2 - 4, 0).render(ms); + } + + + if (mouseX > x && mouseX < x + getLabelWidth(width) && mouseY > y + 5 && mouseY < y + height - 5) { + List tooltip = getLabelTooltip(); + if (tooltip.isEmpty()) + return; + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + Screen screen = Minecraft.getInstance().currentScreen; + ms.push(); + ms.translate(0, 0, 400); + GuiUtils.drawHoveringText(ms, tooltip, mouseX, mouseY, screen.width, screen.height, 300, font); + ms.pop(); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + } + } + + public List getLabelTooltip() { + return labelTooltip; + } + + protected int getLabelWidth(int totalWidth) { + return totalWidth; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/ConfigTextField.java b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigTextField.java new file mode 100644 index 000000000..efa5d886d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/ConfigTextField.java @@ -0,0 +1,34 @@ +package com.simibubi.create.foundation.config.ui; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.util.text.StringTextComponent; + +public class ConfigTextField extends TextFieldWidget { + + protected FontRenderer font; + protected String unit; + + public ConfigTextField(FontRenderer font, int x, int y, int width, int height, String unit) { + super(font, x, y, width, height, StringTextComponent.EMPTY); + this.font = font; + this.unit = unit; + } + + @Override + public void setFocused2(boolean focus) { + super.setFocused2(focus); + + if (!focus) { + if (ConfigScreenList.currentText == this) + ConfigScreenList.currentText = null; + + return; + } + + if (ConfigScreenList.currentText != null && ConfigScreenList.currentText != this) + ConfigScreenList.currentText.setFocused2(false); + + ConfigScreenList.currentText = this; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java b/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java new file mode 100644 index 000000000..7bd018c84 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/SubMenuConfigScreen.java @@ -0,0 +1,345 @@ +package com.simibubi.create.foundation.config.ui; + +import java.awt.Color; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.lwjgl.glfw.GLFW; + +import com.electronwill.nightconfig.core.AbstractConfig; +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.config.ui.entries.BooleanEntry; +import com.simibubi.create.foundation.config.ui.entries.EnumEntry; +import com.simibubi.create.foundation.config.ui.entries.NumberEntry; +import com.simibubi.create.foundation.config.ui.entries.SubMenuEntry; +import com.simibubi.create.foundation.config.ui.entries.ValueEntry; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.ConfirmationScreen; +import com.simibubi.create.foundation.gui.DelegatedStencilElement; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; +import com.simibubi.create.foundation.item.TooltipHelper; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.Couple; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.IGuiEventListener; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.util.text.ITextProperties; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.config.ModConfig; + +public class SubMenuConfigScreen extends ConfigScreen { + + public final ModConfig.Type type; + protected ForgeConfigSpec spec; + protected UnmodifiableConfig configGroup; + protected ConfigScreenList list; + + protected BoxWidget resetAll; + protected BoxWidget saveChanges; + protected BoxWidget discardChanges; + protected BoxWidget goBack; + protected BoxWidget serverLocked; + protected int listWidth; + protected String title; + + + public SubMenuConfigScreen(Screen parent, String title, ModConfig.Type type, ForgeConfigSpec configSpec, UnmodifiableConfig configGroup) { + super(parent); + this.type = type; + this.spec = configSpec; + this.title = title; + this.configGroup = configGroup; + } + + public SubMenuConfigScreen(Screen parent, ModConfig.Type type, ForgeConfigSpec configSpec) { + super(parent); + this.type = type; + this.spec = configSpec; + this.title = "root"; + this.configGroup = configSpec.getValues(); + } + + protected void clearChanges() { + changes.clear(); + list.children() + .stream() + .filter(e -> e instanceof ValueEntry) + .forEach(e -> ((ValueEntry) e).onValueChange()); + } + + protected void saveChanges() { + UnmodifiableConfig values = spec.getValues(); + changes.forEach((path, value) -> { + ForgeConfigSpec.ConfigValue configValue = values.get(path); + configValue.set(value); + if (type == ModConfig.Type.SERVER) { + AllPackets.channel.sendToServer(new CConfigureConfigPacket<>(path, value)); + } + }); + clearChanges(); + } + + protected void resetConfig(UnmodifiableConfig values) { + values.valueMap().forEach((key, obj) -> { + if (obj instanceof AbstractConfig) { + resetConfig((UnmodifiableConfig) obj); + } else if (obj instanceof ForgeConfigSpec.ConfigValue) { + ForgeConfigSpec.ConfigValue configValue = (ForgeConfigSpec.ConfigValue) obj; + ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath()); + + if (!configValue.get().equals(valueSpec.getDefault())) + changes.put(String.join(".", configValue.getPath()), valueSpec.getDefault()); + } + }); + + list.children() + .stream() + .filter(e -> e instanceof ValueEntry) + .forEach(e -> ((ValueEntry) e).onValueChange()); + } + + @Override + public void tick() { + super.tick(); + list.tick(); + } + + @Override + protected void init() { + widgets.clear(); + super.init(); + + listWidth = Math.min(width - 80, 300); + + int yCenter = height / 2; + int listL = this.width / 2 - listWidth / 2; + int listR = this.width / 2 + listWidth / 2; + + resetAll = new BoxWidget(listR + 10, yCenter - 25, 20, 20) + .withPadding(2, 2) + .withCallback((x, y) -> + new ConfirmationScreen() + .at(x, y) + .withText(ITextProperties.plain("You are about to reset all settings for the " + type.toString() + " config. Are you sure?")) + .withAction(success -> { + if (success) + resetConfig(spec.getValues()); + }) + .open(this) + ); + + resetAll.showingElement(AllIcons.I_CONFIG_RESET.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(resetAll))); + resetAll.getToolTip().add(new StringTextComponent("Reset All")); + resetAll.getToolTip().addAll(TooltipHelper.cutStringTextComponent("Click here to reset all configs to their default value.", TextFormatting.GRAY, TextFormatting.GRAY)); + + saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20) + .withPadding(2, 2) + .withCallback((x, y) -> { + if (changes.isEmpty()) + return; + + new ConfirmationScreen() + .at(x, y) + .withText(ITextProperties.plain("You are about to change " + changes.size() + " values. Are you sure?")) + .withAction(success -> { + if (success) + saveChanges(); + }) + .open(this); + }); + saveChanges.showingElement(AllIcons.I_CONFIG_SAVE.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(saveChanges))); + saveChanges.getToolTip().add(new StringTextComponent("Save Changes")); + saveChanges.getToolTip().addAll(TooltipHelper.cutStringTextComponent("Click here to save your current changes.", TextFormatting.GRAY, TextFormatting.GRAY)); + + discardChanges = new BoxWidget(listL - 30, yCenter + 5, 20, 20) + .withPadding(2, 2) + .withCallback((x, y) -> { + if (changes.isEmpty()) + return; + + new ConfirmationScreen() + .at(x, y) + .withText(ITextProperties.plain("You are about to discard " + changes.size() + " unsaved changes. Are you sure?")) + .withAction(success -> { + if (success) + clearChanges(); + }) + .open(this); + }); + discardChanges.showingElement(AllIcons.I_CONFIG_DISCARD.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(discardChanges))); + discardChanges.getToolTip().add(new StringTextComponent("Discard Changes")); + discardChanges.getToolTip().addAll(TooltipHelper.cutStringTextComponent("Click here to discard all the changes you made.", TextFormatting.GRAY, TextFormatting.GRAY)); + + goBack = new BoxWidget(listL - 30, yCenter + 65, 20, 20) + .withPadding(2, 2) + .withCallback(this::attemptBackstep); + goBack.showingElement(AllIcons.I_CONFIG_BACK.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(goBack))); + goBack.getToolTip().add(new StringTextComponent("Go Back")); + + widgets.add(resetAll); + widgets.add(saveChanges); + widgets.add(discardChanges); + widgets.add(goBack); + + list = new ConfigScreenList(client, listWidth, height - 60, 45, height - 15, 40); + list.setLeftPos(this.width / 2 - list.getWidth() / 2); + + children.add(list); + + configGroup.valueMap().forEach((key, obj) -> { + String humanKey = toHumanReadable(key); + + if (obj instanceof AbstractConfig) { + SubMenuEntry entry = new SubMenuEntry(this, humanKey, spec, (UnmodifiableConfig) obj); + list.children().add(entry); + + } else if (obj instanceof ForgeConfigSpec.ConfigValue) { + ForgeConfigSpec.ConfigValue configValue = (ForgeConfigSpec.ConfigValue) obj; + ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath()); + Object value = configValue.get(); + + if (value instanceof Boolean) { + BooleanEntry entry = new BooleanEntry(humanKey, (ForgeConfigSpec.ConfigValue) configValue, valueSpec); + list.children().add(entry); + } else if (value instanceof Enum) { + EnumEntry entry = new EnumEntry(humanKey, (ForgeConfigSpec.ConfigValue>) configValue, valueSpec); + list.children().add(entry); + } else if (value instanceof Number) { + NumberEntry entry = NumberEntry.create(value, humanKey, configValue, valueSpec); + if (entry != null) { + list.children().add(entry); + } else { + list.children().add(new ConfigScreenList.LabeledEntry("n-" + obj.getClass().getSimpleName() + " " + humanKey + " : " + value)); + } + } else { + list.children().add(new ConfigScreenList.LabeledEntry(humanKey + " : " + value)); + } + } + }); + + //extras for server configs + if (type != ModConfig.Type.SERVER) + return; + + list.isForServer = true; + boolean canEdit = client != null && client.player != null && client.player.hasPermissionLevel(2); + + Couple red = Theme.p(Theme.Key.BUTTON_FAIL); + Couple green = Theme.p(Theme.Key.BUTTON_SUCCESS); + + DelegatedStencilElement stencil = new DelegatedStencilElement(); + + serverLocked = new BoxWidget(listR + 10, yCenter + 5, 20, 20) + .withPadding(2, 2) + .showingElement(stencil); + + if (!canEdit) { + list.children().forEach(e -> e.setEditable(false)); + resetAll.active = false; + stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_LOCKED.draw(ms, 0, 0)); + stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, red)); + serverLocked.withBorderColors(red); + serverLocked.getToolTip().add(new StringTextComponent("Locked").formatted(TextFormatting.BOLD)); + serverLocked.getToolTip().addAll(TooltipHelper.cutStringTextComponent("You don't have enough permissions to edit the server config. You can still look at the current values here though.", TextFormatting.GRAY, TextFormatting.GRAY)); + } else { + stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_UNLOCKED.draw(ms, 0, 0)); + stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, green)); + serverLocked.withBorderColors(green); + serverLocked.getToolTip().add(new StringTextComponent("Unlocked").formatted(TextFormatting.BOLD)); + serverLocked.getToolTip().addAll(TooltipHelper.cutStringTextComponent("You have enough permissions to edit the server config. Changes you make here will be synced with the server when you save them.", TextFormatting.GRAY, TextFormatting.GRAY)); + } + + widgets.add(serverLocked); + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.renderWindow(ms, mouseX, mouseY, partialTicks); + + int x = width/2; + drawCenteredString(ms, client.fontRenderer, "Editing config: " + type.toString() + "@" + title, x, 15, Theme.i(Theme.Key.TEXT)); + + list.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + protected void renderWindowForeground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.renderWindowForeground(ms, mouseX, mouseY, partialTicks); + } + + @Override + public void resize(@Nonnull Minecraft client, int width, int height) { + double scroll = list.getScrollAmount(); + init(client, width, height); + list.setScrollAmount(scroll); + } + + @Nullable + @Override + public IGuiEventListener getFocused() { + if (ConfigScreenList.currentText != null) + return ConfigScreenList.currentText; + + return super.getFocused(); + } + + @Override + public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { + if (super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_)) + return true; + + if (code == GLFW.GLFW_KEY_BACKSPACE) { + attemptBackstep(); + } + + return false; + } + + private void attemptBackstep() { + if (!changes.isEmpty() && parent instanceof BaseConfigScreen) { + new ConfirmationScreen() + .centered() + .addText(ITextProperties.plain("You still have " + changes.size() + " unsaved changes for this config.")) + .addText(ITextProperties.plain("Leaving this screen will discard them without saving. Are you sure?")) + .withAction(success -> { + if (!success) + return; + + changes.clear(); + ScreenOpener.open(parent); + }) + .open(this); + } else { + ScreenOpener.open(parent); + } + } + + @Override + public void onClose() { + if (changes.isEmpty()) { + super.onClose(); + return; + } + + new ConfirmationScreen() + .centered() + .addText(ITextProperties.plain("You still have " + changes.size() + " unsaved changes for this config.")) + .addText(ITextProperties.plain("Leaving this screen will discard them without saving. Are you sure?")) + .withAction(success -> { + if (!success) + return; + + changes.clear(); + super.onClose(); + }) + .open(this); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java new file mode 100644 index 000000000..071fa001f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/BooleanEntry.java @@ -0,0 +1,74 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.RenderElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraftforge.common.ForgeConfigSpec; + +public class BooleanEntry extends ValueEntry { + + RenderElement enabled; + RenderElement disabled; + BoxWidget button; + + public BooleanEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + +// enabled = new TextStencilElement(Minecraft.getInstance().fontRenderer, "Enabled") +// .centered(true, true) +// .withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height/2, height, width, 0xff_88f788, 0xff_20cc20)); +// +// disabled = new TextStencilElement(Minecraft.getInstance().fontRenderer, "Disabled") +// .centered(true, true) +// .withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height/2, height, width, 0xff_f78888, 0xff_cc2020)); + + enabled = AllIcons.I_CONFIRM.asStencil() + .withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.p(Theme.Key.BUTTON_SUCCESS))) + .at(10, 0); + + disabled = AllIcons.I_DISABLE.asStencil() + .withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.p(Theme.Key.BUTTON_FAIL))) + .at(10, 0); + + button = new BoxWidget().showingElement(enabled) + .withCallback(() -> setValue(!getValue())); + + listeners.add(button); + onReset(); + } + + @Override + protected void setEditable(boolean b) { + super.setEditable(b); + button.active = b; + } + + @Override + public void tick() { + super.tick(); + button.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, + boolean p_230432_9_, float partialTicks) { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + + button.x = x + width - 80 - resetWidth; + button.y = y + 10; + button.setWidth(35); + button.setHeight(height - 20); + button.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + public void onValueChange(Boolean newValue) { + super.onValueChange(newValue); + button.showingElement(newValue ? enabled : disabled); + bumpCog(newValue ? 15f : -16f); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/EnumEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/EnumEntry.java new file mode 100644 index 000000000..7e44eb10f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/EnumEntry.java @@ -0,0 +1,102 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.BoxElement; +import com.simibubi.create.foundation.gui.DelegatedStencilElement; +import com.simibubi.create.foundation.gui.TextStencilElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraft.client.Minecraft; +import net.minecraftforge.common.ForgeConfigSpec; + +public class EnumEntry extends ValueEntry> { + + protected static final int cycleWidth = 34; + + protected TextStencilElement valueText; + protected BoxWidget cycleLeft; + protected BoxWidget cycleRight; + + public EnumEntry(String label, ForgeConfigSpec.ConfigValue> value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + + valueText = new TextStencilElement(Minecraft.getInstance().fontRenderer, "YEP").centered(true, true); + valueText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, + height, width, Theme.p(Theme.Key.TEXT))); + + DelegatedStencilElement l = AllIcons.I_CONFIG_PREV.asStencil(); + cycleLeft = new BoxWidget(0, 0, cycleWidth + 8, 16).showingElement(l) + .withCallback(() -> cycleValue(-1)); + l.withElementRenderer(BoxWidget.gradientFactory.apply(cycleLeft)); + + DelegatedStencilElement r = AllIcons.I_CONFIG_NEXT.asStencil(); + cycleRight = new BoxWidget(0, 0, cycleWidth + 8, 16).showingElement(r) + .withCallback(() -> cycleValue(1)); + r.at(cycleWidth - 8, 0); + r.withElementRenderer(BoxWidget.gradientFactory.apply(cycleRight)); + + listeners.add(cycleLeft); + listeners.add(cycleRight); + + onReset(); + } + + protected void cycleValue(int direction) { + Enum e = getValue(); + Enum[] options = e.getDeclaringClass() + .getEnumConstants(); + e = options[Math.floorMod(e.ordinal() + direction, options.length)]; + setValue(e); + bumpCog(direction * 15f); + } + + @Override + protected void setEditable(boolean b) { + super.setEditable(b); + cycleLeft.active = b; + cycleLeft.animateGradientFromState(); + cycleRight.active = b; + cycleRight.animateGradientFromState(); + } + + @Override + public void tick() { + super.tick(); + cycleLeft.tick(); + cycleRight.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, + boolean p_230432_9_, float partialTicks) { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + + cycleLeft.x = x + getLabelWidth(width) + 4; + cycleLeft.y = y + 10; + cycleLeft.render(ms, mouseX, mouseY, partialTicks); + + valueText.at(cycleLeft.x + cycleWidth - 8, y + 10, 200) + .withBounds(width - getLabelWidth(width) - 2 * cycleWidth - resetWidth - 4, 16) + .render(ms); + + cycleRight.x = x + width - cycleWidth * 2 - resetWidth + 10; + cycleRight.y = y + 10; + cycleRight.render(ms, mouseX, mouseY, partialTicks); + + new BoxElement() + .withBackground(0) + .flatBorder(0) + .withBounds(10, 10) + .at(cycleLeft.x + cycleWidth + 4, cycleLeft.y + 3) + .render(ms); + } + + @Override + public void onValueChange(Enum newValue) { + super.onValueChange(newValue); + valueText.withText(newValue.name()); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java new file mode 100644 index 000000000..315d147df --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/NumberEntry.java @@ -0,0 +1,211 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import java.lang.reflect.Field; +import java.util.function.Function; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.config.ui.ConfigTextField; +import com.simibubi.create.foundation.gui.TextStencilElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.common.ForgeConfigSpec; + +public abstract class NumberEntry extends ValueEntry { + + protected int minOffset = 0, maxOffset = 0; + protected TextStencilElement minText = null, maxText = null; + protected TextFieldWidget textField; + + @Nullable + public static NumberEntry create(Object type, String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + if (type instanceof Integer) { + return new IntegerEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } else if (type instanceof Float) { + return new FloatEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } else if (type instanceof Double) { + return new DoubleEntry(label, (ForgeConfigSpec.ConfigValue) value, spec); + } + + return null; + } + + public NumberEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + textField = new ConfigTextField(Minecraft.getInstance().fontRenderer, 0, 0, 200, 20, unit); + textField.setText(String.valueOf(getValue())); + textField.setTextColor(Theme.i(Theme.Key.TEXT)); + + Object range = spec.getRange(); + try { + Field minField = range.getClass().getDeclaredField("min"); + Field maxField = range.getClass().getDeclaredField("max"); + minField.setAccessible(true); + maxField.setAccessible(true); + T min = (T) minField.get(range); + T max = (T) maxField.get(range); + + FontRenderer font = Minecraft.getInstance().fontRenderer; + if (min.doubleValue() > getTypeMin().doubleValue()) { + StringTextComponent t = new StringTextComponent(formatBound(min) + " < "); + minText = new TextStencilElement(font, t).centered(true, false); + minText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0 ,0, height/2, height, width, Theme.p(Theme.Key.TEXT_DARKER))); + minOffset = font.getWidth(t); + } + if (max.doubleValue() < getTypeMax().doubleValue()) { + StringTextComponent t = new StringTextComponent(" < " + formatBound(max)); + maxText = new TextStencilElement(font, t).centered(true, false); + maxText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0 ,0, height/2, height, width, Theme.p(Theme.Key.TEXT_DARKER))); + maxOffset = font.getWidth(t); + } + } catch (NoSuchFieldException | IllegalAccessException | ClassCastException | NullPointerException ignored) { + + } + + textField.setResponder(s -> { + try { + T number = getParser().apply(s); + if (!spec.test(number)) + throw new IllegalArgumentException(); + + textField.setTextColor(Theme.i(Theme.Key.TEXT)); + setValue(number); + + } catch (IllegalArgumentException ignored) { + textField.setTextColor(Theme.i(Theme.Key.BUTTON_FAIL)); + } + }); + + listeners.add(textField); + onReset(); + } + + protected String formatBound(T bound) { + String sci = String.format("%.2E", bound.doubleValue()); + String str = String.valueOf(bound); + return sci.length() < str.length() ? sci : str; + } + + protected abstract T getTypeMin(); + + protected abstract T getTypeMax(); + + protected abstract Function getParser(); + + @Override + protected void setEditable(boolean b) { + super.setEditable(b); + textField.setEnabled(b); + } + + @Override + public void onValueChange(T newValue) { + super.onValueChange(newValue); + String newText = String.valueOf(newValue); + if (textField.getText().equals(newText)) + return; + + textField.setText(newText); + } + + @Override + public void tick() { + super.tick(); + textField.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + + textField.x = x + width - 82 - resetWidth; + textField.y = y + 8; + textField.setWidth(Math.min(width - getLabelWidth(width) - resetWidth - minOffset - maxOffset, 40)); + textField.setHeight(20); + textField.render(ms, mouseX, mouseY, partialTicks); + + if (minText != null) + minText + .at(textField.x - minOffset, textField.y, 0) + .withBounds(minOffset, textField.unusedGetHeight()) + .render(ms); + + if (maxText != null) + maxText + .at(textField.x + textField.getWidth(), textField.y, 0) + .withBounds(maxOffset, textField.unusedGetHeight()) + .render(ms); + } + + public static class IntegerEntry extends NumberEntry { + + public IntegerEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Integer getTypeMin() { + return Integer.MIN_VALUE; + } + + @Override + protected Integer getTypeMax() { + return Integer.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Integer::parseInt; + } + } + + public static class FloatEntry extends NumberEntry { + + public FloatEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Float getTypeMin() { + return -Float.MAX_VALUE; + } + + @Override + protected Float getTypeMax() { + return Float.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Float::parseFloat; + } + } + + public static class DoubleEntry extends NumberEntry { + + public DoubleEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label, value, spec); + } + + @Override + protected Double getTypeMin() { + return (double) -Float.MAX_VALUE; + } + + @Override + protected Double getTypeMax() { + return (double) Float.MAX_VALUE; + } + + @Override + protected Function getParser() { + return Double::parseDouble; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java new file mode 100644 index 000000000..d2812f463 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/SubMenuEntry.java @@ -0,0 +1,49 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.config.ui.ConfigScreenList; +import com.simibubi.create.foundation.config.ui.SubMenuConfigScreen; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.DelegatedStencilElement; +import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraftforge.common.ForgeConfigSpec; + +public class SubMenuEntry extends ConfigScreenList.LabeledEntry { + + protected BoxWidget button; + + public SubMenuEntry(SubMenuConfigScreen parent, String label, ForgeConfigSpec spec, UnmodifiableConfig config) { + super(label); + + button = new BoxWidget(0, 0, 35, 16) + .showingElement(AllIcons.I_CONFIG_OPEN.asStencil().at(10, 0)) + .withCallback(() -> ScreenOpener.open(new SubMenuConfigScreen(parent, label, parent.type, spec, config))); + button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(button))); + + listeners.add(button); + } + + @Override + public void tick() { + super.tick(); + button.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + + button.x = x + width - 108; + button.y = y + 10; + button.setHeight(height - 20); + button.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + protected int getLabelWidth(int totalWidth) { + return (int) (totalWidth * labelWidthMult) + 30; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java b/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java new file mode 100644 index 000000000..6f6f89093 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/config/ui/entries/ValueEntry.java @@ -0,0 +1,159 @@ +package com.simibubi.create.foundation.config.ui.entries; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.ArrayUtils; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.config.ui.ConfigScreen; +import com.simibubi.create.foundation.config.ui.ConfigScreenList; +import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.DelegatedStencilElement; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.common.ForgeConfigSpec; + +public class ValueEntry extends ConfigScreenList.LabeledEntry { + + protected static final IFormattableTextComponent modComponent = new StringTextComponent("* ").formatted(TextFormatting.BOLD, TextFormatting.DARK_BLUE).append(StringTextComponent.EMPTY.copy().formatted(TextFormatting.RESET)); + protected static final int resetWidth = 28;//including 6px offset on either side + public static final Pattern unitPattern = Pattern.compile("\\[(in .*)]"); + + protected ForgeConfigSpec.ConfigValue value; + protected ForgeConfigSpec.ValueSpec spec; + protected BoxWidget resetButton; + protected boolean editable = true; + protected String path; + + public ValueEntry(String label, ForgeConfigSpec.ConfigValue value, ForgeConfigSpec.ValueSpec spec) { + super(label); + this.value = value; + this.spec = spec; + this.path = String.join(".", value.getPath()); + + resetButton = new BoxWidget(0, 0, resetWidth - 12, 16) + .showingElement(AllIcons.I_CONFIG_RESET.asStencil()) + .withCallback(() -> { + setValue((T) spec.getDefault()); + this.onReset(); + }); + resetButton.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(resetButton))); + + listeners.add(resetButton); + + List path = value.getPath(); + labelTooltip.add(new StringTextComponent(path.get(path.size()-1)).formatted(TextFormatting.GRAY)); + String comment = spec.getComment(); + if (comment == null || comment.isEmpty()) + return; + String[] commentLines = comment.split("\n"); + //find unit in the comment + for (int i = 0; i < commentLines.length; i++) { + if (commentLines[i].isEmpty()) { + commentLines = ArrayUtils.remove(commentLines, i); + i--; + continue; + } + + Matcher matcher = unitPattern.matcher(commentLines[i]); + if (!matcher.matches()) + continue; + + String u = matcher.group(1); + if (u.equals("in Revolutions per Minute")) + u = "in RPM"; + if (u.equals("in Stress Units")) + u = "in SU"; + unit = u; + } + //add comment to tooltip + labelTooltip.addAll(Arrays.stream(commentLines).map(StringTextComponent::new).collect(Collectors.toList())); + } + + @Override + protected void setEditable(boolean b) { + editable = b; + resetButton.active = editable && !isCurrentValueDefault(); + resetButton.animateGradientFromState(); + } + + @Override + public void tick() { + super.tick(); + resetButton.tick(); + } + + @Override + public void render(MatrixStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) { + if (isCurrentValueChanged()) { + IFormattableTextComponent original = label.getComponent(); + IFormattableTextComponent changed = modComponent.copy().append(original); + label.withText(changed); + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + label.withText(original); + } else { + super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks); + } + + resetButton.x = x + width - resetWidth + 6; + resetButton.y = y + 10; + resetButton.render(ms, mouseX, mouseY, partialTicks); + } + + @Override + protected int getLabelWidth(int totalWidth) { + return (int) (totalWidth * labelWidthMult) + 30; + } + + public void setValue(@Nonnull T value) { + if (value.equals(this.value.get())) { + ConfigScreen.changes.remove(path); + onValueChange(value); + return; + } + + ConfigScreen.changes.put(path, value); + onValueChange(value); + } + + @Nonnull + public T getValue() { + //noinspection unchecked + return (T) ConfigScreen.changes.getOrDefault(path, this.value.get()); + } + + protected boolean isCurrentValueChanged() { + return ConfigScreen.changes.containsKey(path); + } + + protected boolean isCurrentValueDefault() { + return spec.getDefault().equals(getValue()); + } + + public void onReset() { + onValueChange(getValue()); + } + + public void onValueChange() { + onValueChange(getValue()); + } + public void onValueChange(T newValue) { + resetButton.active = editable && !isCurrentValueDefault(); + resetButton.animateGradientFromState(); + } + + protected void bumpCog() {bumpCog(10f);} + protected void bumpCog(float force) { + if (list != null && list instanceof ConfigScreenList) + ((ConfigScreenList) list).bumpCog(force); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java index 9ad3a705e..d76463414 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiContainerScreen.java @@ -69,8 +69,6 @@ public abstract class AbstractSimiContainerScreen extends C RenderSystem.disableLighting(); RenderSystem.disableDepthTest(); renderWindowForeground(matrixStack, mouseX, mouseY, partialTicks); - for (Widget widget : widgets) - widget.renderToolTip(matrixStack, mouseX, mouseY); } @Override @@ -152,9 +150,12 @@ public abstract class AbstractSimiContainerScreen extends C if (!widget.isHovered()) continue; - if (widget instanceof AbstractSimiWidget && !((AbstractSimiWidget) widget).getToolTip() - .isEmpty()) { - renderTooltip(matrixStack, ((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + if (widget instanceof AbstractSimiWidget) { + if (!((AbstractSimiWidget) widget).getToolTip().isEmpty()) + renderTooltip(matrixStack, ((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + + } else { + widget.renderToolTip(matrixStack, mouseX, mouseY); } } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java index 7de342c26..b064ccbfa 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AbstractSimiScreen.java @@ -33,6 +33,13 @@ public abstract class AbstractSimiScreen extends Screen { guiTop = (this.height - sHeight) / 2; } + @Override + public void tick() { + super.tick(); + + widgets.stream().filter(w -> w instanceof AbstractSimiWidget).forEach(w -> ((AbstractSimiWidget) w).tick()); + } + @Override public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { partialTicks = partialTicks == 10 ? 0 @@ -46,8 +53,6 @@ public abstract class AbstractSimiScreen extends Screen { for (Widget widget : widgets) widget.render(ms, mouseX, mouseY, partialTicks); renderWindowForeground(ms, mouseX, mouseY, partialTicks); - for (Widget widget : widgets) - widget.renderToolTip(ms, mouseX, mouseY); ms.pop(); } @@ -62,6 +67,10 @@ public abstract class AbstractSimiScreen extends Screen { for (Widget widget : widgets) if (widget.mouseClicked(x, y, button)) result = true; + + if (!result) { + result = super.mouseClicked(x, y, button); + } return result; } @@ -127,9 +136,12 @@ public abstract class AbstractSimiScreen extends Screen { if (!widget.isHovered()) continue; - if (widget instanceof AbstractSimiWidget && !((AbstractSimiWidget) widget).getToolTip() - .isEmpty()) { - renderTooltip(ms, ((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + if (widget instanceof AbstractSimiWidget) { + if (!((AbstractSimiWidget) widget).getToolTip().isEmpty()) + renderTooltip(ms, ((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + + } else { + widget.renderToolTip(ms, mouseX, mouseY); } } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index 610721e21..4a0abdcab 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.gui; +import java.awt.Color; + import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.Create; @@ -80,8 +82,8 @@ public enum AllGuiTextures implements IScreenRenderable { INDICATOR_YELLOW("widgets.png", 54, 18, 18, 6), INDICATOR_RED("widgets.png", 72, 18, 18, 6), - SPEECH_TOOLTIP("widgets.png", 0, 24, 8, 8), - SPEECH_TOOLTIP_HIGHLIGHT("widgets.png", 8, 24, 8, 8), + SPEECH_TOOLTIP_BACKGROUND("widgets.png", 0, 24, 8, 8), + SPEECH_TOOLTIP_COLOR("widgets.png", 8, 24, 8, 8), // PlacementIndicator PLACEMENT_INDICATOR_SHEET("placement_indicator.png", 0, 0, 16, 256); @@ -123,4 +125,9 @@ public enum AllGuiTextures implements IScreenRenderable { bind(); screen.drawTexture(ms, x, y, startX, startY, width, height); } + + public void draw(MatrixStack ms, int x, int y, Color c) { + bind(); + UIRenderHelper.drawColoredTexture(ms, c, x, y, startX, startY, width, height); + } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java index 5e404da1f..e6b6cc573 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllIcons.java @@ -22,45 +22,121 @@ public class AllIcons implements IScreenRenderable { private int iconX; private int iconY; - public static final AllIcons I_ADD = newRow(), I_TRASH = next(), I_3x3 = next(), I_TARGET = next(), - I_PRIORITY_VERY_LOW = next(), I_PRIORITY_LOW = next(), I_PRIORITY_HIGH = next(), I_PRIORITY_VERY_HIGH = next(), - I_BLACKLIST = next(), I_WHITELIST = next(), I_WHITELIST_OR = next(), I_WHITELIST_AND = next(), - I_WHITELIST_NOT = next(), I_RESPECT_NBT = next(), I_IGNORE_NBT = next(); + public static final AllIcons + I_ADD = newRow(), + I_TRASH = next(), + I_3x3 = next(), + I_TARGET = next(), + I_PRIORITY_VERY_LOW = next(), + I_PRIORITY_LOW = next(), + I_PRIORITY_HIGH = next(), + I_PRIORITY_VERY_HIGH = next(), + I_BLACKLIST = next(), + I_WHITELIST = next(), + I_WHITELIST_OR = next(), + I_WHITELIST_AND = next(), + I_WHITELIST_NOT = next(), + I_RESPECT_NBT = next(), + I_IGNORE_NBT = next(); - public static final AllIcons I_CONFIRM = newRow(), I_NONE = next(), I_OPEN_FOLDER = next(), I_REFRESH = next(), - I_ACTIVE = next(), I_PASSIVE = next(), I_ROTATE_PLACE = next(), I_ROTATE_PLACE_RETURNED = next(), - I_ROTATE_NEVER_PLACE = next(), I_MOVE_PLACE = next(), I_MOVE_PLACE_RETURNED = next(), - I_MOVE_NEVER_PLACE = next(), I_CART_ROTATE = next(), I_CART_ROTATE_PAUSED = next(), + public static final AllIcons + I_CONFIRM = newRow(), + I_NONE = next(), + I_OPEN_FOLDER = next(), + I_REFRESH = next(), + I_ACTIVE = next(), + I_PASSIVE = next(), + I_ROTATE_PLACE = next(), + I_ROTATE_PLACE_RETURNED = next(), + I_ROTATE_NEVER_PLACE = next(), + I_MOVE_PLACE = next(), + I_MOVE_PLACE_RETURNED = next(), + I_MOVE_NEVER_PLACE = next(), + I_CART_ROTATE = next(), + I_CART_ROTATE_PAUSED = next(), I_CART_ROTATE_LOCKED = next(); - - public static final AllIcons I_DONT_REPLACE = newRow(), I_REPLACE_SOLID = next(), I_REPLACE_ANY = next(), - I_REPLACE_EMPTY = next(), I_CENTERED = next(), I_ATTACHED = next(), I_INSERTED = next(), I_FILL = next(), - I_PLACE = next(), I_REPLACE = next(), I_CLEAR = next(), I_OVERLAY = next(), I_FLATTEN = next(), I_LMB = next(), - I_SCROLL = next(), I_RMB = next(); - - public static final AllIcons I_TOOL_DEPLOY = newRow(), I_SKIP_MISSING = next(), I_SKIP_TILES = next(), - I_DICE = next(), I_TUNNEL_SPLIT = next(), I_TUNNEL_FORCED_SPLIT = next(), I_TUNNEL_ROUND_ROBIN = next(), - I_TUNNEL_FORCED_ROUND_ROBIN = next(), I_TUNNEL_PREFER_NEAREST = next(), I_TUNNEL_RANDOMIZE = next(), + + public static final AllIcons + I_DONT_REPLACE = newRow(), + I_REPLACE_SOLID = next(), + I_REPLACE_ANY = next(), + I_REPLACE_EMPTY = next(), + I_CENTERED = next(), + I_ATTACHED = next(), + I_INSERTED = next(), + I_FILL = next(), + I_PLACE = next(), + I_REPLACE = next(), + I_CLEAR = next(), + I_OVERLAY = next(), + I_FLATTEN = next(), + I_LMB = next(), + I_SCROLL = next(), + I_RMB = next(); + + public static final AllIcons + I_TOOL_DEPLOY = newRow(), + I_SKIP_MISSING = next(), + I_SKIP_TILES = next(), + I_DICE = next(), + I_TUNNEL_SPLIT = next(), + I_TUNNEL_FORCED_SPLIT = next(), + I_TUNNEL_ROUND_ROBIN = next(), + I_TUNNEL_FORCED_ROUND_ROBIN = next(), + I_TUNNEL_PREFER_NEAREST = next(), + I_TUNNEL_RANDOMIZE = next(), I_TUNNEL_SYNCHRONIZE = next(), - - I_TOOL_MOVE_XZ = newRow(), I_TOOL_MOVE_Y = next(), I_TOOL_ROTATE = next(), I_TOOL_MIRROR = next(), - I_ARM_ROUND_ROBIN = next(), I_ARM_FORCED_ROUND_ROBIN = next(), I_ARM_PREFER_FIRST = next(), - - I_ADD_INVERTED_ATTRIBUTE = next(), I_FLIP = next(), - - I_PLAY = newRow(), I_PAUSE = next(), I_STOP = next(), I_PLACEMENT_SETTINGS = next(), I_ROTATE_CCW = next(), - I_HOUR_HAND_FIRST = next(), I_MINUTE_HAND_FIRST = next(), I_HOUR_HAND_FIRST_24 = next(), - - I_PATTERN_SOLID = newRow(), I_PATTERN_CHECKERED = next(), I_PATTERN_CHECKERED_INVERSED = next(), + + I_TOOL_MOVE_XZ = newRow(), + I_TOOL_MOVE_Y = next(), + I_TOOL_ROTATE = next(), + I_TOOL_MIRROR = next(), + I_ARM_ROUND_ROBIN = next(), + I_ARM_FORCED_ROUND_ROBIN = next(), + I_ARM_PREFER_FIRST = next(), + + I_ADD_INVERTED_ATTRIBUTE = next(), + I_FLIP = next(), + + I_PLAY = newRow(), + I_PAUSE = next(), + I_STOP = next(), + I_PLACEMENT_SETTINGS = next(), + I_ROTATE_CCW = next(), + I_HOUR_HAND_FIRST = next(), + I_MINUTE_HAND_FIRST = next(), + I_HOUR_HAND_FIRST_24 = next(), + + I_PATTERN_SOLID = newRow(), + I_PATTERN_CHECKERED = next(), + I_PATTERN_CHECKERED_INVERSED = next(), I_PATTERN_CHANCE_25 = next(), - - I_PATTERN_CHANCE_50 = newRow(), I_PATTERN_CHANCE_75 = next(), I_FOLLOW_DIAGONAL = next(), + + I_PATTERN_CHANCE_50 = newRow(), + I_PATTERN_CHANCE_75 = next(), + I_FOLLOW_DIAGONAL = next(), I_FOLLOW_MATERIAL = next(), - + I_SCHEMATIC = newRow(), - I_MTD_LEFT = newRow(), I_MTD_CLOSE = next(), I_MTD_RIGHT = next(), I_MTD_SCAN = next(), I_MTD_REPLAY = next(), - I_MTD_USER_MODE = next(), I_MTD_SLOW_MODE = next(); + I_MTD_LEFT = newRow(), + I_MTD_CLOSE = next(), + I_MTD_RIGHT = next(), + I_MTD_SCAN = next(), + I_MTD_REPLAY = next(), + I_MTD_USER_MODE = next(), + I_MTD_SLOW_MODE = next(), + + I_CONFIG_UNLOCKED = newRow(), + I_CONFIG_LOCKED = next(), + I_CONFIG_DISCARD = next(), + I_CONFIG_SAVE = next(), + I_CONFIG_RESET = next(), + I_CONFIG_BACK = next(), + I_CONFIG_PREV = next(), + I_CONFIG_NEXT = next(), + I_DISABLE = next(), + I_CONFIG_OPEN = next(); public AllIcons(int x, int y) { iconX = x * 16; @@ -116,8 +192,12 @@ public class AllIcons implements IScreenRenderable { } @OnlyIn(Dist.CLIENT) - private void vertex(Entry peek, IVertexBuilder builder, int j, int k, Vector3d rgb, Vector3d vec, float u, - float v) { + public DelegatedStencilElement asStencil() { + return new DelegatedStencilElement().withStencilRenderer((ms, w, h, alpha) -> this.draw(ms, 0, 0)).withBounds(16, 16); + } + + @OnlyIn(Dist.CLIENT) + private void vertex(Entry peek, IVertexBuilder builder, int j, int k, Vector3d rgb, Vector3d vec, float u, float v) { builder.vertex(peek.getModel(), (float) vec.x, (float) vec.y, (float) vec.z) .color((float) rgb.x, (float) rgb.y, (float) rgb.z, 1) .texture(u, v) diff --git a/src/main/java/com/simibubi/create/foundation/gui/BoxElement.java b/src/main/java/com/simibubi/create/foundation/gui/BoxElement.java new file mode 100644 index 000000000..673b057b6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/BoxElement.java @@ -0,0 +1,160 @@ +package com.simibubi.create.foundation.gui; + +import java.awt.Color; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Couple; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.vector.Matrix4f; + +public class BoxElement extends RenderElement { + + protected Color background = new Color(0xff000000, true); + protected Color borderTop = new Color(0x40ffeedd, true); + protected Color borderBot = new Color(0x20ffeedd, true); + protected int borderOffset = 2; + + public T withBackground(Color color) { + this.background = color; + //noinspection unchecked + return (T) this; + } + + public T withBackground(int color) { + return withBackground(new Color(color, true)); + } + + public T flatBorder(Color color) { + this.borderTop = color; + this.borderBot = color; + //noinspection unchecked + return (T) this; + } + + public T flatBorder(int color) { + return flatBorder(new Color(color, true)); + } + + public T gradientBorder(Couple colors) { + this.borderTop = colors.getFirst(); + this.borderBot = colors.getSecond(); + //noinspection unchecked + return (T) this; + } + + public T gradientBorder(Color top, Color bot) { + this.borderTop = top; + this.borderBot = bot; + //noinspection unchecked + return (T) this; + } + + public T gradientBorder(int top, int bot) { + return gradientBorder(new Color(top, true), new Color(bot, true)); + } + + public T withBorderOffset(int offset) { + this.borderOffset = offset; + //noinspection unchecked + return (T) this; + } + + @Override + public void render(MatrixStack ms) { + renderBox(ms); + } + + //total box width = 1 * 2 (outer border) + 1 * 2 (inner color border) + 2 * borderOffset + width + //defaults to 2 + 2 + 4 + 16 = 24px + //batch everything together to save a bunch of gl calls over GuiUtils + protected void renderBox(MatrixStack ms) { + /* + * _____________ + * _|_____________|_ + * | | ___________ | | + * | | | | | | | + * | | | | | | | + * | | |--* | | | | + * | | | h | | | + * | | | --w-+ | | | + * | | | | | | + * | | |_________| | | + * |_|_____________|_| + * |_____________| + * + * */ + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.shadeModel(GL11.GL_SMOOTH); + + int f = borderOffset; + Color c1 = ColorHelper.applyAlpha(background, alpha); + Color c2 = ColorHelper.applyAlpha(borderTop, alpha); + Color c3 = ColorHelper.applyAlpha(borderBot, alpha); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder b = tessellator.getBuffer(); + Matrix4f model = ms.peek().getModel(); + b.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + //outer top + b.vertex(model, x - f - 1 , y - f - 2 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f - 2 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + //outer left + b.vertex(model, x - f - 2 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 2 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + //outer bottom + b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y + f + 2 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + 2 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + //outer right + b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 2 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 2 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + //inner background - also render behind the inner edges + b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex(); + tessellator.draw(); + b.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + //inner top - includes corners + b.vertex(model, x - f - 1 , y - f - 1 , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + //inner left - excludes corners + b.vertex(model, x - f - 1 , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x - f , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x - f , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + //inner bottom - includes corners + b.vertex(model, x - f - 1 , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + //inner right - excludes corners + b.vertex(model, x + f + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + b.vertex(model, x + f + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex(); + b.vertex(model, x + f + 1 + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex(); + + tessellator.draw(); + + RenderSystem.shadeModel(GL11.GL_FLAT); + RenderSystem.disableBlend(); + RenderSystem.enableTexture(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/CombinedStencilElement.java b/src/main/java/com/simibubi/create/foundation/gui/CombinedStencilElement.java new file mode 100644 index 000000000..374479c69 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/CombinedStencilElement.java @@ -0,0 +1,79 @@ +package com.simibubi.create.foundation.gui; + +import javax.annotation.Nonnull; + +import com.mojang.blaze3d.matrix.MatrixStack; + +public class CombinedStencilElement extends StencilElement { + + private StencilElement element1; + private StencilElement element2; + private ElementMode mode; + + private CombinedStencilElement() {} + + public static CombinedStencilElement of(@Nonnull StencilElement element1, @Nonnull StencilElement element2) { + return of(element1, element2, ElementMode.FIRST); + } + + public static CombinedStencilElement of(@Nonnull StencilElement element1, @Nonnull StencilElement element2, ElementMode mode) { + CombinedStencilElement e = new CombinedStencilElement(); + e.element1 = element1; + e.element2 = element2; + e.mode = mode; + return e; + } + + public T withFirst(StencilElement element) { + this.element1 = element; + //noinspection unchecked + return (T) this; + } + + public T withSecond(StencilElement element) { + this.element2 = element; + //noinspection unchecked + return (T) this; + } + + public T withMode(ElementMode mode) { + this.mode = mode; + //noinspection unchecked + return (T) this; + } + + @Override + protected void renderStencil(MatrixStack ms) { + ms.push(); + element1.transform(ms); + element1.withBounds(width, height); + element1.renderStencil(ms); + ms.pop(); + ms.push(); + element2.transform(ms); + element2.withBounds(width, height); + element2.renderStencil(ms); + ms.pop(); + } + + @Override + protected void renderElement(MatrixStack ms) { + if (mode.rendersFirst()) + element1.withBounds(width, height).renderElement(ms); + + if (mode.rendersSecond()) + element2.withBounds(width, height).renderElement(ms); + } + + public enum ElementMode { + FIRST, SECOND, BOTH; + + boolean rendersFirst() { + return this == FIRST || this == BOTH; + } + + boolean rendersSecond() { + return this == SECOND || this == BOTH; + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/ConfirmationScreen.java b/src/main/java/com/simibubi/create/foundation/gui/ConfirmationScreen.java new file mode 100644 index 000000000..9d62f4785 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/ConfirmationScreen.java @@ -0,0 +1,198 @@ +package com.simibubi.create.foundation.gui; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import javax.annotation.Nonnull; + +import org.lwjgl.opengl.GL30; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.text.ITextProperties; +import net.minecraft.util.text.Style; + +public class ConfirmationScreen extends AbstractSimiScreen { + + private Screen source; + private Consumer action = _success -> {}; + private List text = new ArrayList<>(); + private boolean centered = false; + private int x; + private int y; + private int textWidth; + private int textHeight; + + private BoxWidget confirm; + private BoxWidget cancel; + private BoxElement textBackground; + + /* + * Removes text lines from the back of the list + * */ + public ConfirmationScreen removeTextLines(int amount) { + if (amount > text.size()) + return clearText(); + + text.subList(text.size() - amount, text.size()).clear(); + return this; + } + + public ConfirmationScreen clearText() { + this.text.clear(); + return this; + } + + public ConfirmationScreen addText(ITextProperties text) { + this.text.add(text); + return this; + } + + public ConfirmationScreen withText(ITextProperties text) { + return clearText().addText(text); + } + + public ConfirmationScreen at(int x, int y) { + this.x = Math.max(x, 0); + this.y = Math.max(y, 0); + this.centered = false; + return this; + } + + public ConfirmationScreen centered() { + this.centered = true; + return this; + } + + public ConfirmationScreen withAction(Consumer action) { + this.action = action; + return this; + } + + public void open(@Nonnull Screen source) { + this.source = source; + Minecraft client = source.getMinecraft(); + this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); + this.client.currentScreen = this; + } + + @Override + public void tick() { + super.tick(); + confirm.tick(); + cancel.tick(); + } + + @Override + protected void init() { + widgets.clear(); + + ArrayList copy = new ArrayList<>(text); + text.clear(); + copy.forEach(t -> text.addAll(client.fontRenderer.getTextHandler().wrapLines(t, 300, Style.EMPTY))); + + textHeight = text.size() * (client.fontRenderer.FONT_HEIGHT + 1) + 4; + textWidth = 300; + + if (x + textWidth > width) { + x = width - textWidth; + } + + if (y + textHeight + 30 > height) { + y = height - textHeight - 30; + } + + if (centered) { + x = width/2 - textWidth/2 - 2; + y = height/2 - textHeight/2 - 16; + } + + TextStencilElement confirmText = new TextStencilElement(client.fontRenderer, "Confirm").centered(true, true); + confirm = new BoxWidget(x + 4, y + textHeight + 2 , textWidth/2 - 10, 20) + .withCallback(() -> accept(true)); + confirm.showingElement(confirmText.withElementRenderer(BoxWidget.gradientFactory.apply(confirm))); + + TextStencilElement cancelText = new TextStencilElement(client.fontRenderer, "Cancel").centered(true, true); + cancel = new BoxWidget(x + textWidth/2 + 6, y + textHeight + 2, textWidth/2 - 10, 20) + .withCallback(() -> accept(false)); + cancel.showingElement(cancelText.withElementRenderer(BoxWidget.gradientFactory.apply(cancel))); + + widgets.add(confirm); + widgets.add(cancel); + + textBackground = new BoxElement() + .gradientBorder(Theme.p(Theme.Key.BUTTON_DISABLE)) + .withBounds(textWidth, textHeight) + .at(x, y); + + } + + @Override + public void onClose() { + accept(false); + } + + private void accept(boolean success) { + client.currentScreen = source; + action.accept(success); + } + + @Override + protected void renderWindow(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + + textBackground.render(ms); + int offset = client.fontRenderer.FONT_HEIGHT + 1; + int lineY = y - offset; + + ms.push(); + ms.translate(0, 0, 200); + + for (ITextProperties line : text) { + lineY = lineY + offset; + + if (line == null) + continue; + + client.fontRenderer.draw(ms, line.getString(), x, lineY, 0xeaeaea); + } + + ms.pop(); + + } + + @Override + protected void renderWindowBackground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + + UIRenderHelper.framebuffer.framebufferClear(Minecraft.IS_RUNNING_ON_MAC); + //UIRenderHelper.prepFramebufferSize(); + + ms.push(); + //ms.translate(0, 0, -50); + //ms.scale(1, 1, 0.01f); + //todo wait for jozu's framebuffer capabilities on the other branch and use them here + UIRenderHelper.framebuffer.bindFramebuffer(true); + source.render(ms, mouseX, mouseY, 10); + UIRenderHelper.framebuffer.unbindFramebuffer(); + Framebuffer mainBuffer = Minecraft.getInstance().getFramebuffer(); + ms.pop(); + + GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, UIRenderHelper.framebuffer.framebufferObject); + GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, mainBuffer.framebufferObject); + GL30.glBlitFramebuffer(0, 0, mainBuffer.framebufferWidth, mainBuffer.framebufferHeight, 0, 0, mainBuffer.framebufferWidth, mainBuffer.framebufferHeight, GL30.GL_COLOR_BUFFER_BIT, GL30.GL_LINEAR); + mainBuffer.bindFramebuffer(true); + + this.fillGradient(ms, 0, 0, this.width, this.height, 0x70101010, 0x80101010); + //RenderSystem.enableAlphaTest(); + } + + @Override + public void resize(@Nonnull Minecraft client, int width, int height) { + super.resize(client, width, height); + source.resize(client, width, height); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/DelegatedStencilElement.java b/src/main/java/com/simibubi/create/foundation/gui/DelegatedStencilElement.java new file mode 100644 index 000000000..4b45ace4f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/DelegatedStencilElement.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.utility.ColorHelper; + +public class DelegatedStencilElement extends StencilElement { + + protected static final ElementRenderer EMPTY_RENDERER = (ms, width, height, alpha) -> {}; + protected static final ElementRenderer DEFAULT_ELEMENT = (ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, -3, 5, height+4, width+6, ColorHelper.applyAlpha(0xff_10dd10, alpha), ColorHelper.applyAlpha(0xff_1010dd, alpha)); + + protected ElementRenderer stencil; + protected ElementRenderer element; + + public DelegatedStencilElement() { + stencil = EMPTY_RENDERER; + element = DEFAULT_ELEMENT; + } + + public DelegatedStencilElement(ElementRenderer stencil, ElementRenderer element) { + this.stencil = stencil; + this.element = element; + } + + public T withStencilRenderer(ElementRenderer renderer) { + stencil = renderer; + //noinspection unchecked + return (T) this; + } + + public T withElementRenderer(ElementRenderer renderer) { + element = renderer; + //noinspection unchecked + return (T) this; + } + + @Override + protected void renderStencil(MatrixStack ms) { + stencil.render(ms, width, height, 1); + } + + @Override + protected void renderElement(MatrixStack ms) { + element.render(ms, width, height, alpha); + } + + @FunctionalInterface + public interface ElementRenderer { + void render(MatrixStack ms, int width, int height, float alpha); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/GuiGameElement.java b/src/main/java/com/simibubi/create/foundation/gui/GuiGameElement.java index a9b3c24a4..2521be7c5 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/GuiGameElement.java +++ b/src/main/java/com/simibubi/create/foundation/gui/GuiGameElement.java @@ -63,22 +63,22 @@ public class GuiGameElement { .with(FlowingFluidBlock.LEVEL, 0)); } - public static abstract class GuiRenderBuilder { - double xBeforeScale, yBeforeScale, zBeforeScale = 0; - double x, y, z; + public static abstract class GuiRenderBuilder extends RenderElement { + //double xBeforeScale, yBeforeScale, zBeforeScale = 0; + double xLocal, yLocal, zLocal; double xRot, yRot, zRot; double scale = 1; int color = 0xFFFFFF; Vector3d rotationOffset = Vector3d.ZERO; public GuiRenderBuilder atLocal(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; + this.xLocal = x; + this.yLocal = y; + this.zLocal = z; return this; } - public GuiRenderBuilder at(double x, double y) { + /*public GuiRenderBuilder at(double x, double y) { this.xBeforeScale = x; this.yBeforeScale = y; return this; @@ -89,7 +89,7 @@ public class GuiGameElement { this.yBeforeScale = y; this.zBeforeScale = z; return this; - } + }*/ public GuiRenderBuilder rotate(double xRot, double yRot, double zRot) { this.xRot = xRot; @@ -136,9 +136,9 @@ public class GuiGameElement { @Deprecated protected void transform() { - RenderSystem.translated(xBeforeScale, yBeforeScale, 0); + RenderSystem.translated(x, y, 0); RenderSystem.scaled(scale, scale, scale); - RenderSystem.translated(x, y, z); + RenderSystem.translated(xLocal, yLocal, zLocal); RenderSystem.scaled(1, -1, 1); RenderSystem.translated(rotationOffset.x, rotationOffset.y, rotationOffset.z); RenderSystem.rotatef((float) zRot, 0, 0, 1); @@ -148,9 +148,9 @@ public class GuiGameElement { } protected void transformMatrix(MatrixStack matrixStack) { - matrixStack.translate(xBeforeScale, yBeforeScale, zBeforeScale); - matrixStack.scale((float) scale, (float) scale, (float) scale); matrixStack.translate(x, y, z); + matrixStack.scale((float) scale, (float) scale, (float) scale); + matrixStack.translate(xLocal, yLocal, zLocal); matrixStack.scale(1, -1, 1); matrixStack.translate(rotationOffset.x, rotationOffset.y, rotationOffset.z); matrixStack.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion((float) zRot)); diff --git a/src/main/java/com/simibubi/create/foundation/gui/RenderElement.java b/src/main/java/com/simibubi/create/foundation/gui/RenderElement.java new file mode 100644 index 000000000..dcc6a3a0d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/RenderElement.java @@ -0,0 +1,92 @@ +package com.simibubi.create.foundation.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.gui.AbstractGui; + +public abstract class RenderElement implements IScreenRenderable { + + public static RenderElement EMPTY = new RenderElement() {@Override public void render(MatrixStack ms) {}}; + + public static RenderElement of(IScreenRenderable renderable) { + return new SimpleRenderElement(renderable); + } + + protected int width = 16, height = 16; + protected float x = 0, y = 0, z = 0; + protected float alpha = 1f; + + public T at(float x, float y) { + this.x = x; + this.y = y; + //noinspection unchecked + return (T) this; + } + + public T at(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + //noinspection unchecked + return (T) this; + } + + public T withBounds(int width, int height) { + this.width = width; + this.height = height; + //noinspection unchecked + return (T) this; + } + + public T withAlpha(float alpha) { + this.alpha = alpha; + //noinspection unchecked + return (T) this; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public float getX() { + return x; + } + + public float getY() { + return y; + } + + public float getZ() { + return z; + } + + public abstract void render(MatrixStack ms); + + @Override + public void draw(MatrixStack ms, AbstractGui screen, int x, int y) { + this.at(x, y).render(ms); + } + + @Override + public void draw(MatrixStack ms, int x, int y) { + this.at(x, y).render(ms); + } + + public static class SimpleRenderElement extends RenderElement { + + private IScreenRenderable renderable; + + public SimpleRenderElement(IScreenRenderable renderable) { + this.renderable = renderable; + } + + @Override + public void render(MatrixStack ms) { + renderable.draw(ms, (int) x, (int) y); + } + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java b/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java index 9687042ab..cfe1aa1d1 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java +++ b/src/main/java/com/simibubi/create/foundation/gui/ScreenOpener.java @@ -65,7 +65,7 @@ public class ScreenOpener { if (screenHistory.isEmpty()) return false; Screen previouslyRenderedScreen = screenHistory.get(0); - if (!(previouslyRenderedScreen instanceof AbstractSimiScreen)) + if (!(previouslyRenderedScreen instanceof NavigatableSimiScreen)) return false; if (!screen.isEquivalentTo((NavigatableSimiScreen) previouslyRenderedScreen)) return false; diff --git a/src/main/java/com/simibubi/create/foundation/gui/StencilElement.java b/src/main/java/com/simibubi/create/foundation/gui/StencilElement.java new file mode 100644 index 000000000..26677e053 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/StencilElement.java @@ -0,0 +1,51 @@ +package com.simibubi.create.foundation.gui; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.Minecraft; + +public abstract class StencilElement extends RenderElement { + + @Override + public void render(MatrixStack ms) { + ms.push(); + transform(ms); + prepareStencil(ms); + renderStencil(ms); + prepareElement(ms); + renderElement(ms); + cleanUp(ms); + ms.pop(); + } + + protected abstract void renderStencil(MatrixStack ms); + + protected abstract void renderElement(MatrixStack ms); + + protected void transform(MatrixStack ms) { + ms.translate(x, y, z); + } + + protected void prepareStencil(MatrixStack ms) { + GL11.glDisable(GL11.GL_STENCIL_TEST); + RenderSystem.stencilMask(~0); + RenderSystem.clear(GL11.GL_STENCIL_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); + GL11.glEnable(GL11.GL_STENCIL_TEST); + RenderSystem.stencilOp(GL11.GL_REPLACE, GL11.GL_KEEP, GL11.GL_KEEP); + RenderSystem.stencilMask(0xFF); + RenderSystem.stencilFunc(GL11.GL_NEVER, 1, 0xFF); + } + + protected void prepareElement(MatrixStack ms) { + GL11.glEnable(GL11.GL_STENCIL_TEST); + RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); + RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); + } + + protected void cleanUp(MatrixStack ms) { + GL11.glDisable(GL11.GL_STENCIL_TEST); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java b/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java new file mode 100644 index 000000000..f2d5ff943 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/TextStencilElement.java @@ -0,0 +1,80 @@ +package com.simibubi.create.foundation.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.StringTextComponent; + +public class TextStencilElement extends DelegatedStencilElement { + + protected FontRenderer font; + protected IFormattableTextComponent component; + protected boolean centerVertically = false; + protected boolean centerHorizontally = false; + + public TextStencilElement(FontRenderer font) { + super(); + this.font = font; + height = 10; + } + + public TextStencilElement(FontRenderer font, String text) { + this(font); + component = new StringTextComponent(text); + } + + public TextStencilElement(FontRenderer font, IFormattableTextComponent component) { + this(font); + this.component = component; + } + + public TextStencilElement withText(String text) { + component = new StringTextComponent(text); + return this; + } + + public TextStencilElement withText(IFormattableTextComponent component) { + this.component = component; + return this; + } + + public TextStencilElement centered(boolean vertical, boolean horizontal) { + this.centerVertically = vertical; + this.centerHorizontally = horizontal; + return this; + } + + @Override + protected void renderStencil(MatrixStack ms) { + + float x = 0, y = 0; + if (centerHorizontally) + x = width / 2f - font.getWidth(component) / 2f; + + if (centerVertically) + y = height / 2f - font.FONT_HEIGHT / 2f; + + font.draw(ms, component, x, y, 0xff_000000); + //font.draw(ms, component, 0, 0, 0xff_000000); + } + + @Override + protected void renderElement(MatrixStack ms) { + float x = 0, y = 0; + if (centerHorizontally) + x = width / 2f - font.getWidth(component) / 2f; + + if (centerVertically) + y = height / 2f - font.FONT_HEIGHT / 2f; + + ms.push(); + ms.translate(x, y, 0); + element.render(ms, font.getWidth(component), font.FONT_HEIGHT + 2, alpha); + ms.pop(); + } + + public IFormattableTextComponent getComponent() { + return component; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/Theme.java b/src/main/java/com/simibubi/create/foundation/gui/Theme.java new file mode 100644 index 000000000..0f6f0155e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/Theme.java @@ -0,0 +1,177 @@ +package com.simibubi.create.foundation.gui; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.utility.Couple; + +public class Theme { + + private static final Theme base = new Theme(); + private static Theme custom = null; + + public static void setTheme(@Nullable Theme theme) { + custom = theme; + } + + private static ColorHolder resolve(String key) { + ColorHolder h = null; + + if (custom != null) + h = custom.get(key); + + if (h == null) + h = base.get(key); + + if (h == null) + h = ColorHolder.missing; + + return h; + } + + @Nonnull public static Couple p(@Nonnull Key key) {return p(key.get());} + @Nonnull public static Couple p(String key) {return resolve(key).asPair();} + + @Nonnull public static Color c(@Nonnull Key key, boolean first) {return c(key.get(), first);} + @Nonnull public static Color c(String key, boolean first) {return p(key).get(first);} + + public static int i(@Nonnull Key key, boolean first) {return i(key.get(), first);} + public static int i(String key, boolean first) {return p(key).get(first).getRGB();} + + @Nonnull public static Color c(@Nonnull Key key) {return c(key.get());} + @Nonnull public static Color c(String key) {return resolve(key).get();} + + public static int i(@Nonnull Key key) {return i(key.get());} + public static int i(String key) {return resolve(key).get().getRGB();} + + //-----------// + + protected final Map colors; + + protected Theme() { + colors = new HashMap<>(); + init(); + } + + protected void init() { + put(Key.BUTTON_IDLE, new Color(0x60_c0c0ff, true), new Color(0x30_c0c0ff, true)); + put(Key.BUTTON_HOVER, new Color(0xa0_c0c0ff, true), new Color(0x50_c0c0ff, true)); + put(Key.BUTTON_CLICK, new Color(0xff_4b4bff), new Color(0xff_3b3bdd)); + put(Key.BUTTON_DISABLE, new Color(0x80_909090, true), new Color(0x20_909090, true)); + put(Key.BUTTON_SUCCESS, new Color(0xcc_88f788, true), new Color(0xcc_20cc20, true)); + put(Key.BUTTON_FAIL, new Color(0xcc_f78888, true), new Color(0xcc_cc2020, true)); + put(Key.TEXT, new Color(0xff_eeeeee), new Color(0xff_a3a3a3)); + put(Key.TEXT_DARKER, new Color(0xff_a3a3a3), new Color(0xff_808080)); + put(Key.TEXT_ACCENT_STRONG, new Color(0xff_7b7ba3), new Color(0xff_616192)); + put(Key.TEXT_ACCENT_SLIGHT, new Color(0xff_ddeeff), new Color(0xff_a0b0c0)); + put(Key.STREAK, new Color(0x101010, false)); + + put(Key.PONDER_BACKGROUND_TRANSPARENT, new Color(0xdd_000000, true)); + put(Key.PONDER_BACKGROUND_FLAT, new Color(0xff_000000, false)); + put(Key.PONDER_IDLE, new Color(0x40ffeedd, true), new Color(0x20ffeedd, true)); + put(Key.PONDER_HOVER, new Color(0x70ffffff, true), new Color(0x30ffffff, true)); + put(Key.PONDER_HIGHLIGHT, new Color(0xf0ffeedd, true), new Color(0x60ffeedd, true)); + put(Key.TEXT_WINDOW_BORDER, new Color(0x607a6000, true), new Color(0x207a6000, true)); + put(Key.PONDER_BACK_ARROW, new Color(0x70aa9999, true), new Color(0x30aa9999, true)); + put(Key.PONDER_PROGRESSBAR, new Color(0x80ffeedd, true), new Color(0x50ffeedd, true)); + put(Key.PONDER_MISSING_CREATE, new Color(0x70_984500, true), new Color(0x70_692400, true)); + put(Key.PONDER_MISSING_VANILLA, new Color(0x50_5000ff, true), new Color(0x50_300077, true)); + //put(Key., new Color(0x, true), new Color(0x, true)); + } + + protected void put(String key, Color c) { + colors.put(key, ColorHolder.single(c)); + } + + protected void put(Key key, Color c) { + put(key.get(), c); + } + + protected void put(String key, Color c1, Color c2) { + colors.put(key, ColorHolder.pair(c1, c2)); + } + + protected void put(Key key, Color c1, Color c2) { + put(key.get(), c1 , c2); + } + + @Nullable protected ColorHolder get(String key) { + return colors.get(key); + } + + public static class Key { + + public static Key BUTTON_IDLE = new Key(); + public static Key BUTTON_HOVER = new Key(); + public static Key BUTTON_CLICK = new Key(); + public static Key BUTTON_DISABLE = new Key(); + public static Key BUTTON_SUCCESS = new Key(); + public static Key BUTTON_FAIL = new Key(); + + public static Key TEXT = new Key(); + public static Key TEXT_DARKER = new Key(); + public static Key TEXT_ACCENT_STRONG = new Key(); + public static Key TEXT_ACCENT_SLIGHT = new Key(); + + public static Key STREAK = new Key(); + + public static Key PONDER_BACKGROUND_TRANSPARENT = new Key(); + public static Key PONDER_BACKGROUND_FLAT = new Key(); + public static Key PONDER_IDLE = new Key(); + public static Key PONDER_HOVER = new Key(); + public static Key PONDER_HIGHLIGHT = new Key(); + public static Key TEXT_WINDOW_BORDER = new Key(); + public static Key PONDER_BACK_ARROW = new Key(); + public static Key PONDER_PROGRESSBAR = new Key(); + public static Key PONDER_MISSING_CREATE = new Key(); + public static Key PONDER_MISSING_VANILLA = new Key(); + + private static int index = 0; + + private final String s; + + protected Key() { + this.s = "_" + index++; + } + + protected Key(String s) { + this.s = s; + } + + public String get() { + return s; + } + } + + private static class ColorHolder { + + private static final ColorHolder missing = ColorHolder.single(Color.BLACK); + + private Couple colors; + + private static ColorHolder single(Color c) { + ColorHolder h = new ColorHolder(); + h.colors = Couple.create(c, c); + return h; + } + + private static ColorHolder pair(Color first, Color second) { + ColorHolder h = new ColorHolder(); + h.colors = Couple.create(first, second); + return h; + } + + private Color get() { + return colors.getFirst(); + } + + private Couple asPair() { + return colors; + } + + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java index e177813cf..6930d6c87 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java +++ b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java @@ -1,15 +1,21 @@ package com.simibubi.create.foundation.gui; +import java.awt.Color; + +import javax.annotation.Nonnull; + import org.lwjgl.opengl.GL11; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Couple; import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldVertexBufferUploader; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.shader.Framebuffer; import net.minecraft.util.math.vector.Matrix4f; @@ -18,6 +24,10 @@ import net.minecraftforge.fml.client.gui.GuiUtils; public class UIRenderHelper { + public static void enableStencil() { + RenderSystem.recordRenderCall(() -> Minecraft.getInstance().getFramebuffer().enableStencil()); + } + public static Framebuffer framebuffer; public static void init() { @@ -27,19 +37,17 @@ public class UIRenderHelper { framebuffer = new Framebuffer(mainWindow.getFramebufferWidth(), mainWindow.getFramebufferHeight(), true, Minecraft.IS_RUNNING_ON_MAC); framebuffer.setFramebufferColor(0, 0, 0, 0); + framebuffer.enableStencil(); // framebuffer.deleteFramebuffer(); }); } - public static void prepFramebufferSize() { - MainWindow window = Minecraft.getInstance() - .getWindow(); - if (framebuffer.framebufferWidth != window.getFramebufferWidth() - || framebuffer.framebufferHeight != window.getFramebufferHeight()) { - framebuffer.func_216491_a(window.getFramebufferWidth(), window.getFramebufferHeight(), - Minecraft.IS_RUNNING_ON_MAC); + /*public static void prepFramebufferSize() { + MainWindow window = Minecraft.getInstance().getWindow(); + if (framebuffer.framebufferWidth != window.getFramebufferWidth() || framebuffer.framebufferHeight != window.getFramebufferHeight()) { + framebuffer.func_216491_a(window.getFramebufferWidth(), window.getFramebufferHeight(), Minecraft.IS_RUNNING_ON_MAC); } - } + }*/ public static void drawFramebuffer(float alpha) { MainWindow window = Minecraft.getInstance() @@ -51,10 +59,6 @@ public class UIRenderHelper { float ty = (float) framebuffer.framebufferHeight / (float) framebuffer.framebufferTextureHeight; RenderSystem.enableTexture(); - RenderSystem.enableBlend(); - RenderSystem.disableLighting(); - RenderSystem.disableAlphaTest(); - RenderSystem.defaultBlendFunc(); RenderSystem.enableDepthTest(); framebuffer.bindFramebufferTexture(); @@ -82,14 +86,14 @@ public class UIRenderHelper { tessellator.draw(); framebuffer.unbindFramebufferTexture(); - RenderSystem.disableBlend(); - RenderSystem.enableAlphaTest(); } + public static void streak(MatrixStack ms, float angle, int x, int y, int breadth, int length) {streak(ms, angle, x, y, breadth, length, Theme.i(Theme.Key.STREAK));} + // angle in degrees; 0° -> fading to the right // x and y specify the middle point of the starting edge - // width is the total width of the streak - public static void streak(MatrixStack ms, float angle, int x, int y, int width, int length, int color) { + // breadth is the total width of the streak + public static void streak(MatrixStack ms, float angle, int x, int y, int breadth, int length, int color) { int a1 = 0xa0 << 24; int a2 = 0x80 << 24; int a3 = 0x10 << 24; @@ -105,7 +109,7 @@ public class UIRenderHelper { ms.translate(x, y, 0); ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(angle - 90)); - streak(ms, width / 2, length, c1, c2, c3, c4); + streak(ms, breadth / 2, length, c1, c2, c3, c4); ms.pop(); } @@ -120,9 +124,49 @@ public class UIRenderHelper { GuiUtils.drawGradientRect(model, 0, -width, (int) (split2 * height), width, height, c3, c4); } + /** + * @see #angledGradient(MatrixStack, float, int, int, int, int, int, int, int) + */ + public static void angledGradient(@Nonnull MatrixStack ms, float angle, int x, int y, int breadth, int length, Couple c) { + angledGradient(ms, angle, x, y, 0, breadth, length, c); + } + /** + * @see #angledGradient(MatrixStack, float, int, int, int, int, int, int, int) + */ + public static void angledGradient(@Nonnull MatrixStack ms, float angle, int x, int y, int z, int breadth, int length, Couple c) { + angledGradient(ms, angle, x, y, z, breadth, length, c.getFirst().getRGB(), c.getSecond().getRGB()); + } + /** + * @see #angledGradient(MatrixStack, float, int, int, int, int, int, int, int) + */ + public static void angledGradient(@Nonnull MatrixStack ms, float angle, int x, int y, int breadth, int length, int color1, int color2) { + angledGradient(ms, angle, x, y, 0, breadth, length, color1, color2); + } + /** + * x and y specify the middle point of the starting edge + * + * @param angle the angle of the gradient in degrees; 0° means from left to right + * @param color1 the color at the starting edge + * @param color2 the color at the ending edge + * @param breadth the total width of the gradient + * + */ + public static void angledGradient(@Nonnull MatrixStack ms, float angle, int x, int y, int z, int breadth, int length, int color1, int color2) { + ms.push(); + ms.translate(x, y, z); + ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(angle - 90)); + + Matrix4f model = ms.peek().getModel(); + int w = breadth / 2; + GuiUtils.drawGradientRect(model, 0, -w, 0, w, length, color1, color2); + + ms.pop(); + } + + public static void breadcrumbArrow(MatrixStack matrixStack, int x, int y, int z, int width, int height, int indent, Couple colors) {breadcrumbArrow(matrixStack, x, y, z, width, height, indent, colors.getFirst().getRGB(), colors.getSecond().getRGB());} + // draws a wide chevron-style breadcrumb arrow pointing left - public static void breadcrumbArrow(MatrixStack matrixStack, int x, int y, int z, int width, int height, int indent, - int startColor, int endColor) { + public static void breadcrumbArrow(MatrixStack matrixStack, int x, int y, int z, int width, int height, int indent, int startColor, int endColor) { matrixStack.push(); matrixStack.translate(x - indent, y, z); @@ -241,4 +285,30 @@ public class UIRenderHelper { RenderSystem.enableAlphaTest(); RenderSystem.enableTexture(); } + + //just like AbstractGui#drawTexture, but with a color at every vertex + public static void drawColoredTexture(MatrixStack ms, Color c, int x, int y, int tex_left, int tex_top, int width, int height) { + drawColoredTexture(ms, c, x, y, 0, (float)tex_left, (float)tex_top, width, height, 256, 256); + } + + public static void drawColoredTexture(MatrixStack ms, Color c, int x, int y, int z, float tex_left, float tex_top, int width, int height, int sheet_width, int sheet_height) { + drawColoredTexture(ms, c, x, x + width, y, y + height, z, width, height, tex_left, tex_top, sheet_width, sheet_height); + } + + private static void drawColoredTexture(MatrixStack ms, Color c, int left, int right, int top, int bot, int z, int tex_width, int tex_height, float tex_left, float tex_top, int sheet_width, int sheet_height) { + drawTexturedQuad(ms.peek().getModel(), c, left, right, top, bot, z, (tex_left + 0.0F) / (float)sheet_width, (tex_left + (float)tex_width) / (float)sheet_width, (tex_top + 0.0F) / (float)sheet_height, (tex_top + (float)tex_height) / (float)sheet_height); + } + + private static void drawTexturedQuad(Matrix4f m, Color c, int left, int right, int top, int bot, int z, float u1, float u2, float v1, float v2) { + RenderSystem.enableBlend(); + BufferBuilder bufferbuilder = Tessellator.getInstance().getBuffer(); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR_TEXTURE); + bufferbuilder.vertex(m, (float)left , (float)bot, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).texture(u1, v2).endVertex(); + bufferbuilder.vertex(m, (float)right, (float)bot, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).texture(u2, v2).endVertex(); + bufferbuilder.vertex(m, (float)right, (float)top, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).texture(u2, v1).endVertex(); + bufferbuilder.vertex(m, (float)left , (float)top, (float)z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).texture(u1, v1).endVertex(); + bufferbuilder.finishDrawing(); + RenderSystem.enableAlphaTest(); + WorldVertexBufferUploader.draw(bufferbuilder); + } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/AbstractSimiWidget.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/AbstractSimiWidget.java index 2c84c9ccf..f8539a3d3 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/AbstractSimiWidget.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/AbstractSimiWidget.java @@ -2,6 +2,9 @@ package com.simibubi.create.foundation.gui.widgets; import java.util.LinkedList; import java.util.List; +import java.util.function.BiConsumer; + +import javax.annotation.Nonnull; import com.mojang.blaze3d.matrix.MatrixStack; @@ -11,19 +14,78 @@ import net.minecraft.util.text.StringTextComponent; public abstract class AbstractSimiWidget extends Widget { - protected List toolTip; - - public AbstractSimiWidget(int xIn, int yIn, int widthIn, int heightIn) { - super(xIn, yIn, widthIn, heightIn, StringTextComponent.EMPTY); - toolTip = new LinkedList<>(); + protected float z; + protected boolean wasHovered = false; + protected List toolTip = new LinkedList<>(); + protected BiConsumer onClick = (_$, _$$) -> {}; + + protected AbstractSimiWidget() { + this(0, 0); } - + + protected AbstractSimiWidget(int x, int y) { + this(x, y, 16, 16); + } + + protected AbstractSimiWidget(int x, int y, int width, int height) { + super(x, y, width, height, StringTextComponent.EMPTY); + } + + public T withCallback(BiConsumer cb) { + this.onClick = cb; + //noinspection unchecked + return (T) this; + } + + public T withCallback(Runnable cb) { + return withCallback((_$, _$$) -> cb.run()); + } + + public T atZLevel(float z) { + this.z = z; + //noinspection unchecked + return (T) this; + } + public List getToolTip() { return toolTip; } - + + public void tick() {} + @Override - public void renderButton(MatrixStack matrixStack, int p_renderButton_1_, int p_renderButton_2_, float p_renderButton_3_) { + public void render(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + if (visible) { + hovered = isMouseOver(mouseX, mouseY); + beforeRender(ms, mouseX, mouseY, partialTicks); + renderButton(ms, mouseX, mouseY, partialTicks); + afterRender(ms, mouseX, mouseY, partialTicks); + wasHovered = isHovered(); + } } + @Override + public void renderButton(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) {} + + @Override + protected boolean clicked(double mouseX, double mouseY) { + return active && visible && isMouseOver(mouseX, mouseY); + } + + protected void beforeRender(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + ms.push(); + } + + protected void afterRender(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + ms.pop(); + } + + public void runCallback(double mouseX, double mouseY) { + onClick.accept((int) mouseX, (int) mouseY); + } + + @Override + public void onClick(double mouseX, double mouseY) { + runCallback(mouseX, mouseY); + } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/BoxWidget.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/BoxWidget.java new file mode 100644 index 000000000..07b35d4f9 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/BoxWidget.java @@ -0,0 +1,197 @@ +package com.simibubi.create.foundation.gui.widgets; + +import java.awt.Color; +import java.util.function.Function; + +import javax.annotation.Nonnull; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.BoxElement; +import com.simibubi.create.foundation.gui.DelegatedStencilElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.UIRenderHelper; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +public class BoxWidget extends ElementWidget { + + public static final Function gradientFactory = (box) -> (ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, w/2, -2, w + 4, h + 4, box.gradientColor1.getRGB(), box.gradientColor2.getRGB()); + + protected BoxElement box; + + protected Color customBorderTop; + protected Color customBorderBot; + protected boolean animateColors = true; + protected LerpedFloat colorAnimation = LerpedFloat.linear(); + protected Color gradientColor1, gradientColor2; + private Color colorTarget1 = Theme.c(Theme.Key.BUTTON_IDLE, true), colorTarget2 = Theme.c(Theme.Key.BUTTON_IDLE, false); + private Color previousColor1, previousColor2; + + public BoxWidget() { + this(0, 0); + } + + public BoxWidget(int x, int y) { + this(x, y, 16, 16); + } + + public BoxWidget(int x, int y, int width, int height) { + super(x, y, width, height); + box = new BoxElement() + .at(x, y) + .withBounds(width, height); + gradientColor1 = colorTarget1; + gradientColor2 = colorTarget2; + } + + public T withBounds(int width, int height) { + this.width = width; + this.height = height; + //noinspection unchecked + return (T) this; + } + + public T withBorderColors(Couple colors) { + this.customBorderTop = colors.getFirst(); + this.customBorderBot = colors.getSecond(); + updateColorsFromState(); + //noinspection unchecked + return (T) this; + } + + public T withBorderColors(Color top, Color bot) { + this.customBorderTop = top; + this.customBorderBot = bot; + updateColorsFromState(); + //noinspection unchecked + return (T) this; + } + + public T animateColors(boolean b) { + this.animateColors = b; + //noinspection unchecked + return (T) this; + } + + @Override + public void tick() { + super.tick(); + colorAnimation.tickChaser(); + } + + @Override + public void onClick(double x, double y) { + super.onClick(x, y); + + gradientColor1 = Theme.c(Theme.Key.BUTTON_CLICK, true); + gradientColor2 = Theme.c(Theme.Key.BUTTON_CLICK, true); + startGradientAnimation(getColorForState(true), getColorForState(false), true, 0.15); + } + + @Override + protected void beforeRender(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.beforeRender(ms, mouseX, mouseY, partialTicks); + + if (hovered != wasHovered) { + startGradientAnimation( + getColorForState(true), + getColorForState(false), + hovered + ); + } + + if (colorAnimation.settled()) { + gradientColor1 = colorTarget1; + gradientColor2 = colorTarget2; + } else { + float animationValue = 1 - Math.abs(colorAnimation.getValue(partialTicks)); + gradientColor1 = ColorHelper.mixColors(previousColor1, colorTarget1, animationValue); + gradientColor2 = ColorHelper.mixColors(previousColor2, colorTarget2, animationValue); + } + + } + + @Override + public void renderButton(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + float fadeValue = fade.getValue(partialTicks); + if (fadeValue < .1f) + return; + + box.withAlpha(fadeValue); + box.withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_TRANSPARENT)) + .gradientBorder(gradientColor1, gradientColor2) + .at(x, y, z) + .withBounds(width, height) + .render(ms); + + super.renderButton(ms, mouseX, mouseY, partialTicks); + + wasHovered = hovered; + } + + @Override + public boolean isMouseOver(double mX, double mY) { + if (!active || !visible) + return false; + + return + x - 4 <= mX && + y - 4 <= mY && + mX <= x + 4 + width && + mY <= y + 4 + height; + } + + public BoxElement getBox() { + return box; + } + + public void updateColorsFromState() { + colorTarget1 = getColorForState(true); + colorTarget2 = getColorForState(false); + } + + public void animateGradientFromState() { + startGradientAnimation( + getColorForState(true), + getColorForState(false), + true + ); + } + + private void startGradientAnimation(Color c1, Color c2, boolean positive, double expSpeed) { + if (!animateColors) + return; + + colorAnimation.startWithValue(positive ? 1 : -1); + colorAnimation.chase(0, expSpeed, LerpedFloat.Chaser.EXP); + colorAnimation.tickChaser(); + + previousColor1 = gradientColor1; + previousColor2 = gradientColor2; + + colorTarget1 = c1; + colorTarget2 = c2; + } + + private void startGradientAnimation(Color c1, Color c2, boolean positive) { + startGradientAnimation(c1, c2, positive, 0.3); + } + + private Color getColorForState(boolean first) { + if (!active) + return Theme.p(Theme.Key.BUTTON_DISABLE).get(first); + + if (hovered) { + if (first) + return customBorderTop != null ? customBorderTop.darker() : Theme.c(Theme.Key.BUTTON_HOVER, true); + else + return customBorderBot != null ? customBorderBot.darker() : Theme.c(Theme.Key.BUTTON_HOVER, false); + } + + if (first) + return customBorderTop != null ? customBorderTop : Theme.c(Theme.Key.BUTTON_IDLE, true); + else + return customBorderBot != null ? customBorderBot : Theme.c(Theme.Key.BUTTON_IDLE, false); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/ElementWidget.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/ElementWidget.java new file mode 100644 index 000000000..499e81587 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/ElementWidget.java @@ -0,0 +1,144 @@ +package com.simibubi.create.foundation.gui.widgets; + +import java.util.function.Consumer; +import java.util.function.UnaryOperator; + +import javax.annotation.Nonnull; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.IScreenRenderable; +import com.simibubi.create.foundation.gui.RenderElement; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; + +public class ElementWidget extends AbstractSimiWidget { + + protected RenderElement element = RenderElement.EMPTY; + + protected boolean usesFade = false; + protected int fadeModX; + protected int fadeModY; + protected LerpedFloat fade = LerpedFloat.linear().startWithValue(1); + + protected boolean rescaleElement = false; + protected float rescaleSizeX; + protected float rescaleSizeY; + + protected float paddingX = 0; + protected float paddingY = 0; + + public ElementWidget(int x, int y) { + super(x, y); + } + + public ElementWidget(int x, int y, int width, int height) { + super(x, y, width, height); + } + + public T showingElement(RenderElement element) { + this.element = element; + //noinspection unchecked + return (T) this; + } + + public T showing(IScreenRenderable renderable) { + return this.showingElement(RenderElement.of(renderable)); + } + + public T modifyElement(Consumer consumer) { + if (element != null) + consumer.accept(element); + //noinspection unchecked + return (T) this; + } + + public T mapElement(UnaryOperator function) { + if (element != null) + element = function.apply(element); + //noinspection unchecked + return (T) this; + } + + public T withPadding(float paddingX, float paddingY) { + this.paddingX = paddingX; + this.paddingY = paddingY; + //noinspection unchecked + return (T) this; + } + + public T enableFade(int fadeModifierX, int fadeModifierY) { + this.fade.startWithValue(0); + this.usesFade = true; + this.fadeModX = fadeModifierX; + this.fadeModY = fadeModifierY; + //noinspection unchecked + return (T) this; + } + + public T disableFade() { + this.fade.startWithValue(1); + this.usesFade = false; + //noinspection unchecked + return (T) this; + } + + public LerpedFloat fade() { + return fade; + } + + public T fade(float target) { + fade.chase(target, 0.1, LerpedFloat.Chaser.EXP); + //noinspection unchecked + return (T) this; + } + + public T rescaleElement(float rescaleSizeX, float rescaleSizeY) { + this.rescaleElement = true; + this.rescaleSizeX = rescaleSizeX; + this.rescaleSizeY = rescaleSizeY; + //noinspection unchecked + return (T) this; + } + + public T disableRescale() { + this.rescaleElement = false; + //noinspection unchecked + return (T) this; + } + + @Override + public void tick() { + super.tick(); + fade.tickChaser(); + } + + @Override + protected void beforeRender(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.beforeRender(ms, mouseX, mouseY, partialTicks); + + float fadeValue = fade.getValue(partialTicks); + element.withAlpha(fadeValue); + if (fadeValue < 1) { + ms.translate((1 - fadeValue) * fadeModX, (1 - fadeValue) * fadeModY, 0); + } + } + + @Override + public void renderButton(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + ms.push(); + ms.translate(x + paddingX, y + paddingY, z); + float innerWidth = width - 2 * paddingX; + float innerHeight = height - 2 * paddingY; + if (rescaleElement) { + float xScale = innerWidth / rescaleSizeX; + float yScale = innerHeight / rescaleSizeY; + ms.scale(xScale, yScale, 1); + element.at(element.getX() / xScale, element.getY() / yScale); + } + element.withBounds((int) innerWidth, (int) innerHeight).render(ms); + ms.pop(); + } + + public RenderElement getRenderElement() { + return element; + } +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/IconButton.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/IconButton.java index 83049c1de..dcd54ac69 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/IconButton.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/IconButton.java @@ -7,6 +7,8 @@ import com.simibubi.create.foundation.gui.AllIcons; import net.minecraft.util.text.ITextComponent; +import javax.annotation.Nonnull; + public class IconButton extends AbstractSimiWidget { private AllIcons icon; @@ -18,7 +20,7 @@ public class IconButton extends AbstractSimiWidget { } @Override - public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + public void renderButton(@Nonnull MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { if (this.visible) { this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/Indicator.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/Indicator.java index 25df71cb1..627d6b017 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/Indicator.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/Indicator.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.gui.widgets; +import javax.annotation.Nonnull; + import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.foundation.gui.AllGuiTextures; @@ -22,7 +24,7 @@ public class Indicator extends AbstractSimiWidget { } @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks ) { + public void render(@Nonnull MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks ) { AllGuiTextures toDraw; switch(state) { case ON: toDraw = AllGuiTextures.INDICATOR_WHITE; break; diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java index 55e3ea767..3c7d904ca 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/Label.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.gui.widgets; +import javax.annotation.Nonnull; + import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; @@ -69,7 +71,7 @@ public class Label extends AbstractSimiWidget { } @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + public void render(@Nonnull MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { if (!visible) return; if (text == null || text.getString().isEmpty()) diff --git a/src/main/java/com/simibubi/create/foundation/mixin/WindowResizeMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/WindowResizeMixin.java new file mode 100644 index 000000000..5008129b3 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/WindowResizeMixin.java @@ -0,0 +1,29 @@ +package com.simibubi.create.foundation.mixin; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.simibubi.create.foundation.gui.UIRenderHelper; + +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +@Mixin(Minecraft.class) +public class WindowResizeMixin { + + @Shadow @Final private MainWindow mainWindow; + + @Inject(at = @At("TAIL"), method = "updateWindowSize") + private void updateWindowSize(CallbackInfo ci) { + if (UIRenderHelper.framebuffer != null) + UIRenderHelper.framebuffer.func_216491_a(mainWindow.getFramebufferWidth(), mainWindow.getFramebufferHeight(), Minecraft.IS_RUNNING_ON_MAC); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 3e417d17f..faa37475d 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -38,8 +38,9 @@ import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; import com.simibubi.create.content.schematics.packet.SchematicSyncPacket; import com.simibubi.create.content.schematics.packet.SchematicUploadPacket; -import com.simibubi.create.foundation.command.ConfigureConfigPacket; +import com.simibubi.create.foundation.command.SConfigureConfigPacket; import com.simibubi.create.foundation.command.HighlightPacket; +import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket; import com.simibubi.create.foundation.utility.ServerSpeedProvider; @@ -80,12 +81,13 @@ public enum AllPackets { PLACE_EJECTOR(EjectorPlacementPacket.class, EjectorPlacementPacket::new, PLAY_TO_SERVER), TRIGGER_EJECTOR(EjectorTriggerPacket.class, EjectorTriggerPacket::new, PLAY_TO_SERVER), EJECTOR_ELYTRA(EjectorElytraPacket.class, EjectorElytraPacket::new, PLAY_TO_SERVER), + C_CONFIGURE_CONFIG(CConfigureConfigPacket.class, CConfigureConfigPacket::new, PLAY_TO_SERVER), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new, PLAY_TO_CLIENT), BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new, PLAY_TO_CLIENT), - CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new, PLAY_TO_CLIENT), + S_CONFIGURE_CONFIG(SConfigureConfigPacket.class, SConfigureConfigPacket::new, PLAY_TO_CLIENT), CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new, PLAY_TO_CLIENT), CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new, PLAY_TO_CLIENT), GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new, PLAY_TO_CLIENT), diff --git a/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java index 9f834b83c..bf0d2adb7 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/NavigatableSimiScreen.java @@ -9,9 +9,11 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.lwjgl.glfw.GLFW; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.IScreenRenderable; import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.ponder.content.PonderTagScreen; import com.simibubi.create.foundation.ponder.ui.PonderButton; @@ -76,9 +78,9 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { if (screen instanceof PonderTagScreen) icon = ((PonderTagScreen) screen).getTag(); - widgets.add(backTrack = new PonderButton(31, height - 31 - PonderButton.SIZE, () -> { - ScreenOpener.openPreviousScreen(this, Optional.empty()); - }).fade(0, -1)); + widgets.add(backTrack = new PonderButton(31, height - 31 - 20) + .enableFade(0, 5) + .withCallback(() -> ScreenOpener.openPreviousScreen(this, Optional.empty()))); backTrack.fade(1); if (icon != null) @@ -97,7 +99,7 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { ms.push(); ms.translate(0, 0, 500); if (backTrack.isHovered()) { - textRenderer.draw(ms, Lang.translate(THINK_BACK), 15, height - 16, 0xffa3a3a3); + textRenderer.draw(ms, Lang.translate(THINK_BACK), 15, height - 16, Theme.i(Theme.Key.TEXT_DARKER)); if (MathHelper.epsilonEquals(arrowAnimation.getValue(), arrowAnimation.getChaseTarget())) { arrowAnimation.setValue(1); arrowAnimation.setValue(1);// called twice to also set the previous value to 1 @@ -108,7 +110,18 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { @Override protected void renderWindowBackground(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { - if (transition.getChaseTarget() == 0) { + if (backTrack != null) { + int x = (int) MathHelper.lerp(arrowAnimation.getValue(partialTicks), -9, 21); + int maxX = backTrack.x + backTrack.getWidth(); + + if (x + 30 < backTrack.x) + UIRenderHelper.breadcrumbArrow(ms, x + 30, height - 51, 0, maxX - (x + 30), 20, 5, Theme.p(Theme.Key.PONDER_BACK_ARROW)); + + UIRenderHelper.breadcrumbArrow(ms, x, height - 51, 0, 30, 20, 5, Theme.p(Theme.Key.PONDER_BACK_ARROW)); + UIRenderHelper.breadcrumbArrow(ms, x - 30, height - 51, 0, 30, 20, 5, Theme.p(Theme.Key.PONDER_BACK_ARROW)); + } + + if (transition.getChaseTarget() == 0 || transition.settled()) { renderBackground(ms); return; } @@ -123,11 +136,11 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { if (lastScreen != null && lastScreen != this && !transition.settled()) { ms.push();// 1 UIRenderHelper.framebuffer.framebufferClear(Minecraft.IS_RUNNING_ON_MAC); - UIRenderHelper.prepFramebufferSize(); + //UIRenderHelper.prepFramebufferSize(); ms.push();// 2 ms.translate(0, 0, -1000); UIRenderHelper.framebuffer.bindFramebuffer(true); - lastScreen.render(ms, mouseX, mouseY, 10); + lastScreen.render(ms, mouseX, mouseY, partialTicks); ms.pop();// 2 // use the buffer texture @@ -149,7 +162,12 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { ms.translate(dpx, dpy, 0); ms.scale((float) scale, (float) scale, 1); ms.translate(-dpx, -dpy, 0); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.disableAlphaTest(); UIRenderHelper.drawFramebuffer(1f - Math.abs(transitionValue)); + RenderSystem.disableBlend(); + RenderSystem.enableAlphaTest(); ms.pop();// 1 } @@ -158,18 +176,6 @@ public abstract class NavigatableSimiScreen extends AbstractSimiScreen { ms.translate(depthPointX, depthPointY, 0); ms.scale((float) scale, (float) scale, 1); ms.translate(-depthPointX, -depthPointY, 0); - - if (backTrack != null) { - int x = (int) MathHelper.lerp(arrowAnimation.getValue(partialTicks), -9, 21); - int maxX = backTrack.x + backTrack.getWidth(); - - if (x + 30 < backTrack.x) - UIRenderHelper.breadcrumbArrow(ms, x + 30, height - 51, 0, maxX - (x + 30), 20, 5, 0x40aa9999, - 0x10aa9999); - - UIRenderHelper.breadcrumbArrow(ms, x, height - 51, 0, 30, 20, 5, 0x40aa9999, 0x10aa9999); - UIRenderHelper.breadcrumbArrow(ms, x - 30, height - 51, 0, 30, 20, 5, 0x40aa9999, 0x10aa9999); - } } @Override diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java index e19eaa51f..1adeca3b8 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderProgressBar.java @@ -1,9 +1,13 @@ package com.simibubi.create.foundation.ponder; +import javax.annotation.Nonnull; + +import org.antlr.v4.runtime.misc.IntegerList; + import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.BoxElement; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; -import com.simibubi.create.foundation.utility.AnimationTickHolder; -import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.animation.LerpedFloat; import it.unimi.dsi.fastutil.ints.IntList; @@ -15,7 +19,6 @@ import net.minecraftforge.fml.client.gui.GuiUtils; public class PonderProgressBar extends AbstractSimiWidget { LerpedFloat progress; - LerpedFloat flash; PonderUI ponder; @@ -25,27 +28,12 @@ public class PonderProgressBar extends AbstractSimiWidget { this.ponder = ponder; progress = LerpedFloat.linear() .startWithValue(0); - flash = LerpedFloat.linear() - .startWithValue(0); } public void tick() { progress.chase(ponder.getActiveScene() .getSceneProgress(), .5f, LerpedFloat.Chaser.EXP); progress.tickChaser(); - - if (hovered) - flash(); - } - - public void flash() { - float value = flash.getValue(); - flash.setValue(value + (1 - value) * .2f); - } - - public void dim() { - float value = flash.getValue(); - flash.setValue(value * .5f); } @Override @@ -102,58 +90,47 @@ public class PonderProgressBar extends AbstractSimiWidget { } @Override - public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + public void renderButton(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { hovered = clicked(mouseX, mouseY); - ms.push(); - ms.translate(0, 0, 250); - /* - * ponderButtons are at z+400 - * renderBox is at z+100 - * gradients have to be in front of the box so z>+100 - */ + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.PONDER_IDLE)) + .at(x, y, 250) + .withBounds(width, height) + .render(ms); + ms.push(); - PonderUI.renderBox(ms, x, y, width, height, false); - ms.pop(); - - ms.push(); - ms.translate(x - 2, y - 2, 0); + ms.translate(x - 2, y - 2, 150); ms.push(); ms.scale((width + 4) * progress.getValue(partialTicks), 1, 1); - GuiUtils.drawGradientRect(ms.peek() - .getModel(), 110, 0, 3, 1, 4, 0x80ffeedd, 0x80ffeedd); - GuiUtils.drawGradientRect(ms.peek() - .getModel(), 110, 0, 4, 1, 5, 0x50ffeedd, 0x50ffeedd); + int c1 = Theme.i(Theme.Key.PONDER_PROGRESSBAR, true); + int c2 = Theme.i(Theme.Key.PONDER_PROGRESSBAR, false); + GuiUtils.drawGradientRect(ms.peek().getModel(), 110, 0, 3, 1, 4, c1, c1); + GuiUtils.drawGradientRect(ms.peek().getModel(), 110, 0, 4, 1, 5, c2, c2); ms.pop(); renderKeyframes(ms, mouseX, partialTicks); ms.pop(); - - ms.pop(); } private void renderKeyframes(MatrixStack ms, int mouseX, float partialTicks) { PonderScene activeScene = ponder.getActiveScene(); - int hoverStartColor; - int hoverEndColor; + int hoverStartColor = Theme.i(Theme.Key.PONDER_HOVER, true) | 0xa0_000000; + int hoverEndColor = Theme.i(Theme.Key.PONDER_HOVER, false) | 0xa0_000000; + int idleStartColor = Theme.i(Theme.Key.PONDER_IDLE, true) | 0x40_000000; + int idleEndColor = Theme.i(Theme.Key.PONDER_IDLE, false) | 0x40_000000; int hoverIndex; if (hovered) { hoverIndex = getHoveredKeyframeIndex(activeScene, mouseX); - float flashValue = flash.getValue(partialTicks) * 3 - + (float) Math.sin((AnimationTickHolder.getTicks() + partialTicks) / 6); - - hoverEndColor = ColorHelper.applyAlpha(0x70ffffff, flashValue); - hoverStartColor = ColorHelper.applyAlpha(0x30ffffff, flashValue); } else { hoverIndex = -2; - hoverEndColor = 0; - hoverStartColor = 0; } IntList keyframeTimes = activeScene.keyframeTimes; @@ -167,8 +144,8 @@ public class PonderProgressBar extends AbstractSimiWidget { int keyframePos = (int) (((float) keyframeTime) / ((float) activeScene.totalTime) * (width + 4)); boolean selected = i == hoverIndex; - int startColor = selected ? hoverStartColor : 0x30ffeedd; - int endColor = selected ? hoverEndColor : 0x60ffeedd; + int startColor = selected ? hoverStartColor : idleStartColor; + int endColor = selected ? hoverEndColor : idleEndColor; int height = selected ? 8 : 4; drawKeyframe(ms, activeScene, selected, keyframeTime, keyframePos, startColor, endColor, height); @@ -176,8 +153,7 @@ public class PonderProgressBar extends AbstractSimiWidget { } } - private void drawKeyframe(MatrixStack ms, PonderScene activeScene, boolean selected, int keyframeTime, - int keyframePos, int startColor, int endColor, int height) { + private void drawKeyframe(MatrixStack ms, PonderScene activeScene, boolean selected, int keyframeTime, int keyframePos, int startColor, int endColor, int height) { if (selected) { FontRenderer font = Minecraft.getInstance().fontRenderer; GuiUtils.drawGradientRect(ms.peek() diff --git a/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java b/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java index 2e9c14f23..3b8657ef3 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/PonderUI.java @@ -2,13 +2,13 @@ package com.simibubi.create.foundation.ponder; import static com.simibubi.create.foundation.ponder.PonderLocalization.LANG_PREFIX; +import java.awt.Color; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.stream.IntStream; -import org.apache.commons.lang3.mutable.MutableBoolean; import org.lwjgl.opengl.GL11; import com.mojang.blaze3d.matrix.MatrixStack; @@ -16,8 +16,10 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; +import com.simibubi.create.foundation.gui.BoxElement; import com.simibubi.create.foundation.gui.GuiGameElement; import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.ponder.PonderScene.SceneTransform; import com.simibubi.create.foundation.ponder.content.DebugScenes; @@ -29,6 +31,7 @@ import com.simibubi.create.foundation.ponder.elements.TextWindowElement; import com.simibubi.create.foundation.ponder.ui.PonderButton; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.FontHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; @@ -43,14 +46,12 @@ import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.widget.Widget; -import net.minecraft.client.settings.KeyBinding; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MutableBoundingBox; -import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.text.IFormattableTextComponent; @@ -166,13 +167,16 @@ public class PonderUI extends NavigatableSimiScreen { int i = tagButtons.size(); int x = 31; int y = 81 + i * 30; - PonderButton b = new PonderButton(x, y, (mouseX, mouseY) -> { - centerScalingOn(mouseX, mouseY); - ScreenOpener.transitionTo(new PonderTagScreen(t)); - }).showing(t); - widgets.add(b); - tagButtons.add(b); + PonderButton b2 = new PonderButton(x, y) + .showing(t) + .withCallback((mX, mY) -> { + centerScalingOn(mX, mY); + ScreenOpener.transitionTo(new PonderTagScreen(t)); + }); + + widgets.add(b2); + tagButtons.add(b2); LerpedFloat chase = LerpedFloat.linear() .startWithValue(0) @@ -181,10 +185,10 @@ public class PonderUI extends NavigatableSimiScreen { }); - if (chapter != null) { + /*if (chapter != null) { widgets.add(chap = new PonderButton(width - 31 - 24, 31, () -> { }).showing(chapter)); - } + }*/ GameSettings bindings = client.gameSettings; int spacing = 8; @@ -193,53 +197,63 @@ public class PonderUI extends NavigatableSimiScreen { { int pX = (width / 2) - 110; - int pY = bY + PonderButton.SIZE + 4; + int pY = bY + 20 + 4; int pW = width - 2 * pX; widgets.add(progressBar = new PonderProgressBar(this, pX, pY, pW, 1)); } - widgets.add(scan = new PonderButton(bX, bY, () -> { - identifyMode = !identifyMode; - if (!identifyMode) - scenes.get(index) - .deselect(); - else - ponderPartialTicksPaused = client.getRenderPartialTicks(); - }).showing(AllIcons.I_MTD_SCAN) - .shortcut(bindings.keyBindDrop) - .fade(0, -1)); - - widgets.add(slowMode = new PonderButton(width - 20 - 31, bY, () -> { - setComfyReadingEnabled(!isComfyReadingEnabled()); - }).showing(AllIcons.I_MTD_SLOW_MODE) - .fade(0, -1)); + widgets.add(scan = new PonderButton(bX, bY) + .withShortcut(bindings.keyBindDrop) + .showing(AllIcons.I_MTD_SCAN) + .enableFade(0, 5) + .withCallback(() -> { + identifyMode = !identifyMode; + if (!identifyMode) + scenes.get(index) + .deselect(); + else + ponderPartialTicksPaused = client.getRenderPartialTicks(); + })); + widgets.add(slowMode = new PonderButton(width - 20 - 31, bY) + .showing(AllIcons.I_MTD_SLOW_MODE) + .enableFade(0, 5) + .withCallback(() -> setComfyReadingEnabled(!isComfyReadingEnabled()))); + if (PonderIndex.EDITOR_MODE) { - widgets.add(userMode = new PonderButton(width - 50 - 31, bY, () -> { - userViewMode = !userViewMode; - }).showing(AllIcons.I_MTD_USER_MODE) - .fade(0, -1)); + widgets.add(userMode = new PonderButton(width - 50 - 31, bY) + .showing(AllIcons.I_MTD_USER_MODE) + .enableFade(0, 5) + .withCallback(() -> userViewMode = !userViewMode)); } bX += 50 + spacing; - widgets.add(left = new PonderButton(bX, bY, () -> this.scroll(false)).showing(AllIcons.I_MTD_LEFT) - .shortcut(bindings.keyBindLeft) - .fade(0, -1)); + widgets.add(left = new PonderButton(bX, bY) + .withShortcut(bindings.keyBindLeft) + .showing(AllIcons.I_MTD_LEFT) + .enableFade(0, 5) + .withCallback(() -> this.scroll(false))); bX += 20 + spacing; - widgets.add(close = new PonderButton(bX, bY, this::onClose).showing(AllIcons.I_MTD_CLOSE) - .shortcut(bindings.keyBindInventory) - .fade(0, -1)); + widgets.add(close = new PonderButton(bX, bY) + .withShortcut(bindings.keyBindInventory) + .showing(AllIcons.I_MTD_CLOSE) + .enableFade(0, 5) + .withCallback(this::onClose)); bX += 20 + spacing; - widgets.add(right = new PonderButton(bX, bY, () -> this.scroll(true)).showing(AllIcons.I_MTD_RIGHT) - .shortcut(bindings.keyBindRight) - .fade(0, -1)); + widgets.add(right = new PonderButton(bX, bY) + .withShortcut(bindings.keyBindRight) + .showing(AllIcons.I_MTD_RIGHT) + .enableFade(0, 5) + .withCallback(() -> this.scroll(true))); bX += 50 + spacing; - widgets.add(replay = new PonderButton(bX, bY, this::replay).showing(AllIcons.I_MTD_REPLAY) - .shortcut(bindings.keyBindBack) - .fade(0, -1)); + widgets.add(replay = new PonderButton(bX, bY) + .withShortcut(bindings.keyBindBack) + .showing(AllIcons.I_MTD_REPLAY) + .enableFade(0, 5) + .withCallback(this::replay)); } @Override @@ -527,17 +541,16 @@ public class PonderUI extends NavigatableSimiScreen { float lazyIndexValue = lazyIndex.getValue(partialTicks); float indexDiff = Math.abs(lazyIndexValue - index); PonderScene activeScene = scenes.get(index); - int textColor = 0xeeeeee; boolean noWidgetsHovered = true; for (Widget widget : widgets) noWidgetsHovered &= !widget.isMouseOver(mouseX, mouseY); - int tooltipColor = 0xffa3a3a3; + int tooltipColor = Theme.i(Theme.Key.TEXT_DARKER); { // Chapter title ms.push(); - ms.translate(0, 0, 300); + ms.translate(0, 0, 100); int x = 31 + 20 + 8; int y = 31; @@ -545,14 +558,21 @@ public class PonderUI extends NavigatableSimiScreen { int wordWrappedHeight = textRenderer.getWordWrappedHeight(title, left.x - 51); int streakHeight = 35 - 9 + wordWrappedHeight; - UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (150 * fade), 0x101010); - UIRenderHelper.streak(ms, 180, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (30 * fade), 0x101010); - renderBox(ms, 21, 21, 30, 30, false); + UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (150 * fade)); + UIRenderHelper.streak(ms, 180, x - 4, y - 12 + streakHeight / 2, streakHeight, (int) (30 * fade)); + //renderBox(ms, 21, 21, 30, 30, false); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.PONDER_IDLE)) + .at(21, 21, 100) + .withBounds(30, 30) + .render(ms); + GuiGameElement.of(stack) - .at(x - 39, y - 11) - .scale(2) - .render(ms); + .scale(2) + .at(x - 39, y - 11) + .render(ms); textRenderer.draw(ms, Lang.translate(PONDERING), x, y - 6, tooltipColor); y += 8; @@ -562,19 +582,18 @@ public class PonderUI extends NavigatableSimiScreen { ms.multiply(Vector3f.NEGATIVE_X.getDegreesQuaternion(indexDiff * -75)); ms.translate(0, 0, 5); FontHelper.drawSplitString(ms, textRenderer, title, 0, 0, left.x - 51, - ColorHelper.applyAlpha(textColor, 1 - indexDiff)); + ColorHelper.applyAlpha(Theme.i(Theme.Key.TEXT), 1 - indexDiff)); ms.pop(); if (chapter != null) { ms.push(); ms.translate(chap.x - 4 - 4, chap.y, 0); - UIRenderHelper.streak(ms, 180, 4, 10, 26, (int) (150 * fade), 0x101010); + UIRenderHelper.streak(ms, 180, 4, 10, 26, (int) (150 * fade)); - drawRightAlignedString(textRenderer, ms, Lang.translate(IN_CHAPTER) - .getString(), 0, 0, tooltipColor); - drawRightAlignedString(textRenderer, ms, Lang.translate(LANG_PREFIX + "chapter." + chapter.getId()) - .getString(), 0, 12, 0xffeeeeee); + drawRightAlignedString(textRenderer, ms, Lang.translate(IN_CHAPTER).getString(), 0, 0, tooltipColor); + drawRightAlignedString(textRenderer, ms, + Lang.translate(LANG_PREFIX + "chapter." + chapter.getId()).getString(), 0, 12, Theme.i(Theme.Key.TEXT)); ms.pop(); } @@ -590,29 +609,24 @@ public class PonderUI extends NavigatableSimiScreen { ms.push(); ms.translate(mouseX, mouseY, 100); if (hoveredTooltipItem.isEmpty()) { - IFormattableTextComponent text = Lang - .translate(IDENTIFY_MODE, - ((IFormattableTextComponent) client.gameSettings.keyBindDrop.getBoundKeyLocalizedText()) - .formatted(TextFormatting.WHITE)) - .formatted(TextFormatting.GRAY); + IFormattableTextComponent text = Lang.translate( + IDENTIFY_MODE, + ((IFormattableTextComponent) client.gameSettings.keyBindDrop.getBoundKeyLocalizedText()).formatted(TextFormatting.WHITE) + ).formatted(TextFormatting.GRAY); - // renderOrderedTooltip(ms, textRenderer.wrapLines(text, width / 3), 0, 0); - renderWrappedToolTip(ms, textRenderer.getTextHandler() - .wrapLines(text, width / 3, Style.EMPTY), 0, 0, textRenderer); - /* - * String tooltip = Lang - * .createTranslationTextComponent(IDENTIFY_MODE, client.gameSettings.keyBindDrop.getBoundKeyLocalizedText().applyTextStyle(TextFormatting.WHITE)) - * .applyTextStyle(TextFormatting.GRAY) - * .getFormattedText(); - * renderTooltip(font.listFormattedStringToWidth(tooltip, width / 3), 0, 0); - */ + //renderOrderedTooltip(ms, textRenderer.wrapLines(text, width / 3), 0, 0); + renderWrappedToolTip(ms, textRenderer.getTextHandler().wrapLines(text, width / 3, Style.EMPTY), 0, 0, textRenderer); + /*String tooltip = Lang + .createTranslationTextComponent(IDENTIFY_MODE, client.gameSettings.keyBindDrop.getBoundKeyLocalizedText().applyTextStyle(TextFormatting.WHITE)) + .applyTextStyle(TextFormatting.GRAY) + .getFormattedText(); + renderTooltip(font.listFormattedStringToWidth(tooltip, width / 3), 0, 0);*/ } else renderTooltip(ms, hoveredTooltipItem, 0, 0); if (hoveredBlockPos != null && PonderIndex.EDITOR_MODE && !userViewMode) { ms.translate(0, -15, 0); boolean copied = copiedBlockPos != null && hoveredBlockPos.equals(copiedBlockPos); - IFormattableTextComponent coords = new StringTextComponent( - hoveredBlockPos.getX() + ", " + hoveredBlockPos.getY() + ", " + hoveredBlockPos.getZ()) + IFormattableTextComponent coords = new StringTextComponent(hoveredBlockPos.getX() + ", " + hoveredBlockPos.getY() + ", " + hoveredBlockPos.getZ()) .formatted(copied ? TextFormatting.GREEN : TextFormatting.GOLD); renderTooltip(ms, coords, 0, 0); } @@ -649,15 +663,14 @@ public class PonderUI extends NavigatableSimiScreen { // Widgets widgets.forEach(w -> { if (w instanceof PonderButton) { - PonderButton mtdButton = (PonderButton) w; - mtdButton.fade(fade); + ((PonderButton) w).fade().startWithValue(fade); } }); if (index == 0 || index == 1 && lazyIndexValue < index) - left.fade(lazyIndexValue); + left.fade().startWithValue(lazyIndexValue); if (index == scenes.size() - 1 || index == scenes.size() - 2 && lazyIndexValue > index) - right.fade(scenes.size() - lazyIndexValue - 1); + right.fade().startWithValue(scenes.size() - lazyIndexValue - 1); boolean finished = activeScene.isFinished(); if (finished) @@ -693,14 +706,14 @@ public class PonderUI extends NavigatableSimiScreen { ms.translate(x, y + 5 * (1 - fade), 800); float fadedWidth = 200 * chase.getValue(partialTicks); - UIRenderHelper.streak(ms, 0, 0, 12, 26, (int) fadedWidth, 0x101010); + UIRenderHelper.streak(ms, 0, 0, 12, 26, (int) fadedWidth); GL11.glScissor((int) (x * s), 0, (int) (fadedWidth * s), (int) (height * s)); GL11.glEnable(GL11.GL_SCISSOR_TEST); String tagName = this.tags.get(i) .getTitle(); - textRenderer.draw(ms, tagName, 3, 8, 0xffeedd); + textRenderer.draw(ms, tagName, 3, 8, Theme.i(Theme.Key.TEXT_ACCENT_SLIGHT)); GL11.glDisable(GL11.GL_SCISSOR_TEST); @@ -727,8 +740,7 @@ public class PonderUI extends NavigatableSimiScreen { ms.pop(); } - protected void lowerButtonGroup(MatrixStack ms, int index, int mouseX, int mouseY, float fade, AllIcons icon, - KeyBinding key) { + /*protected void lowerButtonGroup(MatrixStack ms, int index, int mouseX, int mouseY, float fade, AllIcons icon, KeyBinding key) { int bWidth = 20; int bHeight = 20; int bX = (width - bWidth) / 2 + (index - 1) * (bWidth + 8); @@ -740,10 +752,9 @@ public class PonderUI extends NavigatableSimiScreen { boolean hovered = isMouseOver(mouseX, mouseY, bX, bY, bWidth, bHeight); renderBox(ms, bX, bY, bWidth, bHeight, hovered); icon.draw(ms, bX + 2, bY + 2); - drawCenteredText(ms, textRenderer, key.getBoundKeyLocalizedText(), bX + bWidth / 2 + 8, bY + bHeight - 6, - 0xff606060); + drawCenteredText(ms, textRenderer, key.getBoundKeyLocalizedText(), bX + bWidth / 2 + 8, bY + bHeight - 6, 0xff606060); ms.pop(); - } + }*/ private void renderOverlay(MatrixStack ms, int i, float partialTicks) { if (identifyMode) @@ -756,7 +767,7 @@ public class PonderUI extends NavigatableSimiScreen { @Override public boolean mouseClicked(double x, double y, int button) { - MutableBoolean handled = new MutableBoolean(false); + /*MutableBoolean handled = new MutableBoolean(false); widgets.forEach(w -> { if (handled.booleanValue()) return; @@ -771,7 +782,7 @@ public class PonderUI extends NavigatableSimiScreen { }); if (handled.booleanValue()) - return true; + return true;*/ if (identifyMode && hoveredBlockPos != null && PonderIndex.EDITOR_MODE) { long handle = client.getWindow() @@ -843,8 +854,8 @@ public class PonderUI extends NavigatableSimiScreen { .getString(); return stack.getItem() - .getName() - .getString(); + .getName() + .getString(); } public FontRenderer getFontRenderer() { @@ -857,13 +868,8 @@ public class PonderUI extends NavigatableSimiScreen { return hovered; } - public static void renderBox(MatrixStack ms, int x, int y, int w, int h, boolean highlighted) { - renderBox(ms, x, y, w, h, 0xff000000, highlighted ? 0xf0ffeedd : 0x40ffeedd, - highlighted ? 0x60ffeedd : 0x20ffeedd); - } - - public static void renderSpeechBox(MatrixStack ms, int x, int y, int w, int h, boolean highlighted, - Pointing pointing, boolean returnWithLocalTransform) { + public static void renderSpeechBox(MatrixStack ms, int x, int y, int w, int h, boolean highlighted, Pointing pointing, + boolean returnWithLocalTransform) { if (!returnWithLocalTransform) ms.push(); @@ -875,6 +881,8 @@ public class PonderUI extends NavigatableSimiScreen { int divotSize = 8; int distance = 1; int divotRadius = divotSize / 2; + Couple borderColors = Theme.p(highlighted ? Theme.Key.PONDER_HIGHLIGHT : Theme.Key.PONDER_IDLE); + Color c; switch (pointing) { default: @@ -884,6 +892,7 @@ public class PonderUI extends NavigatableSimiScreen { boxY -= h + divotSize + 1 + distance; divotX -= divotRadius; divotY -= divotSize + distance; + c = borderColors.getSecond(); break; case LEFT: divotRotation = 90; @@ -891,6 +900,7 @@ public class PonderUI extends NavigatableSimiScreen { boxY -= h / 2; divotX += distance; divotY -= divotRadius; + c = ColorHelper.mixColors(borderColors, 0.5f); break; case RIGHT: divotRotation = 270; @@ -898,6 +908,7 @@ public class PonderUI extends NavigatableSimiScreen { boxY -= h / 2; divotX -= divotSize + distance; divotY -= divotRadius; + c = ColorHelper.mixColors(borderColors, 0.5f); break; case UP: divotRotation = 180; @@ -905,17 +916,24 @@ public class PonderUI extends NavigatableSimiScreen { boxY += divotSize + 1 + distance; divotX -= divotRadius; divotY += distance; + c = borderColors.getFirst(); break; } - renderBox(ms, boxX, boxY, w, h, highlighted); + //renderBox(ms, boxX, boxY, w, h, highlighted); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(borderColors) + .at(boxX, boxY, 100) + .withBounds(w, h) + .render(ms); ms.push(); - AllGuiTextures toRender = highlighted ? AllGuiTextures.SPEECH_TOOLTIP_HIGHLIGHT : AllGuiTextures.SPEECH_TOOLTIP; ms.translate(divotX + divotRadius, divotY + divotRadius, 10); ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(divotRotation)); ms.translate(-divotRadius, -divotRadius, 0); - toRender.draw(ms, 0, 0); + AllGuiTextures.SPEECH_TOOLTIP_BACKGROUND.draw(ms, 0, 0); + AllGuiTextures.SPEECH_TOOLTIP_COLOR.draw(ms, 0, 0, c); ms.pop(); if (returnWithLocalTransform) { @@ -927,23 +945,20 @@ public class PonderUI extends NavigatableSimiScreen { } - public static void renderBox(MatrixStack ms, int x, int y, int w, int h, int backgroundColor, int borderColorStart, + /*public static void renderBox(MatrixStack ms, int x, int y, int w, int h, int backgroundColor, int borderColorStart, int borderColorEnd) { int z = 100; - Matrix4f model = ms.peek() - .getModel(); + Matrix4f model = ms.peek().getModel(); GuiUtils.drawGradientRect(model, z, x - 3, y - 4, x + w + 3, y - 3, backgroundColor, backgroundColor); GuiUtils.drawGradientRect(model, z, x - 3, y + h + 3, x + w + 3, y + h + 4, backgroundColor, backgroundColor); GuiUtils.drawGradientRect(model, z, x - 3, y - 3, x + w + 3, y + h + 3, backgroundColor, backgroundColor); GuiUtils.drawGradientRect(model, z, x - 4, y - 3, x - 3, y + h + 3, backgroundColor, backgroundColor); GuiUtils.drawGradientRect(model, z, x + w + 3, y - 3, x + w + 4, y + h + 3, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(model, z, x - 3, y - 3 + 1, x - 3 + 1, y + h + 3 - 1, borderColorStart, - borderColorEnd); - GuiUtils.drawGradientRect(model, z, x + w + 2, y - 3 + 1, x + w + 3, y + h + 3 - 1, borderColorStart, - borderColorEnd); + GuiUtils.drawGradientRect(model, z, x - 3, y - 3 + 1, x - 3 + 1, y + h + 3 - 1, borderColorStart, borderColorEnd); + GuiUtils.drawGradientRect(model, z, x + w + 2, y - 3 + 1, x + w + 3, y + h + 3 - 1, borderColorStart, borderColorEnd); GuiUtils.drawGradientRect(model, z, x - 3, y - 3, x + w + 3, y - 3 + 1, borderColorStart, borderColorStart); GuiUtils.drawGradientRect(model, z, x - 3, y + h + 2, x + w + 3, y + h + 3, borderColorEnd, borderColorEnd); - } + }*/ public ItemStack getHoveredTooltipItem() { return hoveredTooltipItem; diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java index 8166eabf6..e9a0a8097 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndexScreen.java @@ -10,6 +10,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock; import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.ponder.NavigatableSimiScreen; import com.simibubi.create.foundation.ponder.PonderRegistry; @@ -106,17 +107,17 @@ public class PonderIndexScreen extends NavigatableSimiScreen { int itemCenterY = (int) (height * itemYmult); for (Item item : items) { - PonderButton button = - new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4, (x, y) -> { - if (!PonderRegistry.all.containsKey(item.getRegistryName())) - return; + PonderButton b = new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4) + .showing(new ItemStack(item)) + .withCallback((x, y) -> { + if (!PonderRegistry.all.containsKey(item.getRegistryName())) + return; - centerScalingOn(x, y); - ScreenOpener.transitionTo(PonderUI.of(new ItemStack(item))); - }).showing(new ItemStack(item)); + centerScalingOn(x, y); + ScreenOpener.transitionTo(PonderUI.of(new ItemStack(item))); + }); - button.fade(1); - widgets.add(button); + widgets.add(b); layout.next(); } @@ -158,8 +159,8 @@ public class PonderIndexScreen extends NavigatableSimiScreen { ms.push(); ms.translate(x, y, 0); - UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220, 0x101010); - textRenderer.draw(ms, "Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, 0xffddeeff); + UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220); + textRenderer.draw(ms, "Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, Theme.i(Theme.Key.TEXT)); ms.pop(); } @@ -170,8 +171,8 @@ public class PonderIndexScreen extends NavigatableSimiScreen { ms.push(); ms.translate(x, y, 0); - UIRenderHelper.streak(ms, 0, itemArea.getX() - 10, itemArea.getY() - 20, 20, 220, 0x101010); - textRenderer.draw(ms, "Items to inspect", itemArea.getX() - 5, itemArea.getY() - 25, 0xffddeeff); + UIRenderHelper.streak(ms, 0, itemArea.getX() - 10, itemArea.getY() - 20, 20, 220); + textRenderer.draw(ms, "Items to inspect", itemArea.getX() - 5, itemArea.getY() - 25, Theme.i(Theme.Key.TEXT)); ms.pop(); } @@ -189,7 +190,7 @@ public class PonderIndexScreen extends NavigatableSimiScreen { ms.pop(); } - @Override + /*@Override public boolean mouseClicked(double x, double y, int button) { MutableBoolean handled = new MutableBoolean(false); widgets.forEach(w -> { @@ -207,7 +208,7 @@ public class PonderIndexScreen extends NavigatableSimiScreen { if (handled.booleanValue()) return true; return super.mouseClicked(x, y, button); - } + }*/ @Override public boolean isEquivalentTo(NavigatableSimiScreen other) { diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java index 321b7c6d6..1e430d63f 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderTagScreen.java @@ -9,7 +9,9 @@ import org.apache.commons.lang3.mutable.MutableBoolean; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.Create; +import com.simibubi.create.foundation.gui.BoxElement; import com.simibubi.create.foundation.gui.ScreenOpener; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.ponder.NavigatableSimiScreen; import com.simibubi.create.foundation.ponder.PonderLocalization; @@ -84,24 +86,26 @@ public class PonderTagScreen extends NavigatableSimiScreen { int itemCenterY = getItemsY(); for (Item i : items) { - final boolean canClick = PonderRegistry.all.containsKey(i.getRegistryName()); - PonderButton button = - new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4, (mouseX, mouseY) -> { - if (!canClick) - return; + PonderButton b = new PonderButton(itemCenterX + layout.getX() + 4, itemCenterY + layout.getY() + 4) + .showing(new ItemStack(i)); + + if (PonderRegistry.all.containsKey(i.getRegistryName())) { + b.withCallback((mouseX, mouseY) -> { centerScalingOn(mouseX, mouseY); ScreenOpener.transitionTo(PonderUI.of(new ItemStack(i), tag)); - }).showing(new ItemStack(i)); - if (!canClick) + }); + } else { if (i.getRegistryName() - .getNamespace() - .equals(Create.ID)) - button.customColors(0x70984500, 0x70692400); + .getNamespace() + .equals(Create.ID)) + b.withBorderColors(Theme.p(Theme.Key.PONDER_MISSING_CREATE)) + .animateColors(false); else - button.customColors(0x505000FF, 0x50300077); + b.withBorderColors(Theme.p(Theme.Key.PONDER_MISSING_VANILLA)) + .animateColors(false); + } - button.fade(1); - widgets.add(button); + widgets.add(b); layout.next(); } @@ -109,23 +113,26 @@ public class PonderTagScreen extends NavigatableSimiScreen { ResourceLocation registryName = tag.getMainItem() .getItem() .getRegistryName(); - final boolean canClick = PonderRegistry.all.containsKey(registryName); - PonderButton button = - new PonderButton(itemCenterX - layout.getTotalWidth() / 2 - 42, itemCenterY - 10, (mouseX, mouseY) -> { - if (!canClick) - return; - centerScalingOn(mouseX, mouseY); - ScreenOpener.transitionTo(PonderUI.of(tag.getMainItem(), tag)); - }).showing(tag.getMainItem()); - if (!canClick) + + PonderButton b = new PonderButton(itemCenterX - layout.getTotalWidth() / 2 - 42, itemCenterY - 10) + .showing(tag.getMainItem()); + + if (PonderRegistry.all.containsKey(registryName)) { + b.withCallback((mouseX, mouseY) -> { + centerScalingOn(mouseX, mouseY); + ScreenOpener.transitionTo(PonderUI.of(tag.getMainItem(), tag)); + }); + } else { if (registryName.getNamespace() .equals(Create.ID)) - button.customColors(0x70984500, 0x70692400); + b.withBorderColors(Theme.p(Theme.Key.PONDER_MISSING_CREATE)) + .animateColors(false); else - button.customColors(0x505000FF, 0x50300077); + b.withBorderColors(Theme.p(Theme.Key.PONDER_MISSING_VANILLA)) + .animateColors(false); + } - button.fade(1); - widgets.add(button); + widgets.add(b); } // chapters @@ -187,15 +194,21 @@ public class PonderTagScreen extends NavigatableSimiScreen { String title = tag.getTitle(); int streakHeight = 35; - UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, 240, 0x101010); - PonderUI.renderBox(ms, 21, 21, 30, 30, false); + UIRenderHelper.streak(ms, 0, x - 4, y - 12 + streakHeight / 2, streakHeight, 240); + //PonderUI.renderBox(ms, 21, 21, 30, 30, false); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.PONDER_IDLE)) + .at(21, 21, 100) + .withBounds(30, 30) + .render(ms); - textRenderer.draw(ms, Lang.translate(PonderUI.PONDERING), x, y - 6, 0xffa3a3a3); + textRenderer.draw(ms, Lang.translate(PonderUI.PONDERING), x, y - 6, Theme.i(Theme.Key.TEXT_DARKER)); y += 8; x += 0; ms.translate(x, y, 0); ms.translate(0, 0, 5); - textRenderer.draw(ms, title, 0, 0, 0xeeeeee); + textRenderer.draw(ms, title, 0, 0, Theme.i(Theme.Key.TEXT)); ms.pop(); ms.push(); @@ -214,9 +227,16 @@ public class PonderTagScreen extends NavigatableSimiScreen { int h = textRenderer.getWordWrappedHeight(desc, w); - PonderUI.renderBox(ms, x - 3, y - 3, w + 6, h + 6, false); + //PonderUI.renderBox(ms, x - 3, y - 3, w + 6, h + 6, false); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.PONDER_IDLE)) + .at(x - 3, y - 3, 90) + .withBounds(w + 6, h + 6) + .render(ms); + ms.translate(0, 0, 100); - FontHelper.drawSplitString(ms, textRenderer, desc, x, y, w, 0xeeeeee); + FontHelper.drawSplitString(ms, textRenderer, desc, x, y, w, Theme.i(Theme.Key.TEXT)); ms.pop(); } @@ -232,16 +252,23 @@ public class PonderTagScreen extends NavigatableSimiScreen { ms.push(); ms.translate(x, y, 0); - PonderUI.renderBox(ms, (sWidth - stringWidth) / 2 - 5, itemArea.getY() - 21, stringWidth + 10, 10, false); + //PonderUI.renderBox(ms, (sWidth - stringWidth) / 2 - 5, itemArea.getY() - 21, stringWidth + 10, 10, false); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.PONDER_IDLE)) + .at((sWidth - stringWidth) / 2f - 5, itemArea.getY() - 21, 100) + .withBounds(stringWidth + 10, 10) + .render(ms); + ms.translate(0, 0, 200); // UIRenderHelper.streak(0, itemArea.getX() - 10, itemArea.getY() - 20, 20, 180, 0x101010); - drawCenteredString(ms, textRenderer, relatedTitle, sWidth / 2, itemArea.getY() - 20, 0xeeeeee); + drawCenteredString(ms, textRenderer, relatedTitle, sWidth / 2, itemArea.getY() - 20, Theme.i(Theme.Key.TEXT)); ms.translate(0,0, -200); - UIRenderHelper.streak(ms, 0, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75, 0x101010); - UIRenderHelper.streak(ms, 180, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75, 0x101010); + UIRenderHelper.streak(ms, 0, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75); + UIRenderHelper.streak(ms, 180, 0, 0, itemArea.getHeight() + 10, itemArea.getWidth() / 2 + 75); ms.pop(); @@ -261,8 +288,8 @@ public class PonderTagScreen extends NavigatableSimiScreen { ms.push(); ms.translate(chapterX, chapterY, 0); - UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220, 0x101010); - textRenderer.draw(ms, "More Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, 0xffddeeff); + UIRenderHelper.streak(ms, 0, chapterArea.getX() - 10, chapterArea.getY() - 20, 20, 220); + textRenderer.draw(ms, "More Topics to Ponder about", chapterArea.getX() - 5, chapterArea.getY() - 25, Theme.i(Theme.Key.TEXT_ACCENT_SLIGHT)); ms.pop(); } @@ -291,7 +318,7 @@ public class PonderTagScreen extends NavigatableSimiScreen { return hoveredItem; } - @Override + /*@Override public boolean mouseClicked(double x, double y, int button) { MutableBoolean handled = new MutableBoolean(false); widgets.forEach(w -> { @@ -310,7 +337,7 @@ public class PonderTagScreen extends NavigatableSimiScreen { if (handled.booleanValue()) return true; return super.mouseClicked(x, y, button); - } + }*/ @Override public boolean isEquivalentTo(NavigatableSimiScreen other) { diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java index 7f8badfb3..f87c70c28 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/InputWindowElement.java @@ -136,7 +136,7 @@ public class InputWindowElement extends AnimatedOverlayElement { if (hasItem) { GuiGameElement.of(item) - .at(keyWidth + (hasIcon ? 24 : 0), 0) + .at(keyWidth + (hasIcon ? 24 : 0), 0) .scale(1.5) .render(ms); RenderSystem.disableDepthTest(); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java index 865a83100..31da2fb41 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/TextWindowElement.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.function.Supplier; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.BoxElement; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.ponder.PonderLocalization; import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.ponder.PonderUI; @@ -110,7 +112,14 @@ public class TextWindowElement extends AnimatedOverlayElement { ms.push(); ms.translate(0, sceneToScreen.y, 400); - PonderUI.renderBox(ms, targetX - 10, 3, boxWidth, boxHeight - 1, 0xaa000000, 0x30eebb00, 0x10eebb00); + new BoxElement() + .withBackground(Theme.c(Theme.Key.PONDER_BACKGROUND_FLAT)) + .gradientBorder(Theme.p(Theme.Key.TEXT_WINDOW_BORDER)) + .at(targetX - 10, 3, 100) + .withBounds(boxWidth, boxHeight - 1) + .render(ms); + + //PonderUI.renderBox(ms, targetX - 10, 3, boxWidth, boxHeight - 1, 0xaa000000, 0x30eebb00, 0x10eebb00); int brighterColor = ColorHelper.mixAlphaColors(color, 0xFFffffdd, 1 / 2f); if (vec != null) { diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java b/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java index a50f1432f..c77273bab 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/ui/ChapterLabel.java @@ -5,6 +5,7 @@ import java.util.function.BiConsumer; import javax.annotation.Nonnull; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; import com.simibubi.create.foundation.ponder.content.PonderChapter; @@ -20,17 +21,18 @@ public class ChapterLabel extends AbstractSimiWidget { public ChapterLabel(PonderChapter chapter, int x, int y, BiConsumer onClick) { super(x, y, 175, 38); - this.button = new PonderButton(x + 4, y + 4, onClick, 30, 30).showing(chapter); - this.button.fade(1); + this.button = new PonderButton(x + 4, y + 4, 30, 30) + .showing(chapter) + .withCallback(onClick); this.chapter = chapter; } @Override public void render(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { - UIRenderHelper.streak(ms, 0, x, y + height / 2, height - 2, width, 0x101010); + UIRenderHelper.streak(ms, 0, x, y + height / 2, height - 2, width); Minecraft.getInstance().fontRenderer.draw(ms, Lang.translate("ponder.chapter." + chapter.getId()), x + 50, - y + 20, 0xffddeeff); + y + 20, Theme.i(Theme.Key.TEXT_ACCENT_SLIGHT)); button.renderButton(ms, mouseX, mouseY, partialTicks); super.render(ms, mouseX, mouseY, partialTicks); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java b/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java index fb40f8784..2533e3e9a 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/ui/PonderButton.java @@ -1,175 +1,105 @@ package com.simibubi.create.foundation.ponder.ui; -import java.util.function.BiConsumer; +import java.awt.Color; + +import javax.annotation.Nonnull; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.gui.GuiGameElement; -import com.simibubi.create.foundation.gui.IScreenRenderable; -import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget; -import com.simibubi.create.foundation.ponder.PonderUI; +import com.simibubi.create.foundation.gui.RenderElement; +import com.simibubi.create.foundation.gui.Theme; +import com.simibubi.create.foundation.gui.widgets.BoxWidget; +import com.simibubi.create.foundation.gui.widgets.ElementWidget; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.ColorHelper; -import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; -public class PonderButton extends AbstractSimiWidget { +public class PonderButton extends BoxWidget { - private IScreenRenderable icon; - private ItemStack item; - protected boolean pressed; - private BiConsumer onClick; - private int xFadeModifier; - private int yFadeModifier; - private float fade; - private KeyBinding shortcut; - private LerpedFloat flash; - private Couple customPassiveBorder; + protected ItemStack item; + protected KeyBinding shortcut; + protected LerpedFloat flash = LerpedFloat.linear().startWithValue(0).chase(0, 0.1f, LerpedFloat.Chaser.EXP); - public static final int SIZE = 20; + public PonderButton(int x, int y) { + this(x, y, 20, 20); + } - public PonderButton(int x, int y, BiConsumer onClick, int width, int height) { + public PonderButton(int x, int y, int width, int height) { super(x, y, width, height); - this.onClick = onClick; - flash = LerpedFloat.linear() - .startWithValue(0); + z = 400; + paddingX = 2; + paddingY = 2; } - public PonderButton(int x, int y, BiConsumer onClick) { - this(x, y, onClick, SIZE, SIZE); - } - - public PonderButton(int x, int y, Runnable onClick) { - this(x, y, ($, $$) -> onClick.run()); - } - - public PonderButton showing(IScreenRenderable icon) { - this.icon = icon; - return this; - } - - public PonderButton showing(ItemStack item) { - this.item = item; - return this; - } - - public PonderButton customColors(int start, int end) { - this.customPassiveBorder = Couple.create(start, end); - return this; - } - - public PonderButton shortcut(KeyBinding key) { + public T withShortcut(KeyBinding key) { this.shortcut = key; - return this; + //noinspection unchecked + return (T) this; } - public PonderButton fade(int xModifier, int yModifier) { - this.xFadeModifier = xModifier; - this.yFadeModifier = yModifier; - return this; + public T showing(ItemStack item) { + this.item = item; + return super.showingElement(GuiGameElement.of(item) + .scale(1.5f) + .at(-4, -4)); } - public void fade(float fade) { - this.fade = fade; + @Override + public T showingElement(RenderElement element) { + return super.showingElement(element); } public void flash() { - float value = flash.getValue(); - flash.setValue(value + (1 - value) * .2f); + flash.updateChaseTarget(1); } public void dim() { - float value = flash.getValue(); - flash.setValue(value * .5f); + flash.updateChaseTarget(0); } @Override - public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { - if (!visible) - return; - if (fade < .1f) - return; + public void tick() { + super.tick(); + flash.tickChaser(); + } - hovered = isMouseOver(mouseX, mouseY) && fade > .75f; - - ms.push(); - RenderSystem.disableDepthTest(); - if (fade < 1) - ms.translate((1 - fade) * -5 * xFadeModifier, (1 - fade) * -5 * yFadeModifier, 0); + @Override + protected void beforeRender(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.beforeRender(ms, mouseX, mouseY, partialTicks); float flashValue = flash.getValue(partialTicks); - if (flashValue > .1f) - fade *= 3 * flashValue + Math.sin((PonderUI.ponderTicks + partialTicks) / 6); - - int backgroundColor = ColorHelper.applyAlpha(0xdd000000, fade); - int borderColorStart = customPassiveBorder != null ? customPassiveBorder.getFirst() : hovered ? 0x70ffffff : 0x40aa9999; - int borderColorEnd = customPassiveBorder != null ? customPassiveBorder.getSecond() : hovered ? 0x30ffffff : 0x20aa9999; - borderColorStart = ColorHelper.applyAlpha(borderColorStart, fade); - borderColorEnd = ColorHelper.applyAlpha(borderColorEnd, fade); - - ms.translate(0, 0, 400); - PonderUI.renderBox(ms, x, y, width, height, backgroundColor, borderColorStart, borderColorEnd); - ms.translate(0, 0, 100); - - if (icon != null) { - RenderSystem.enableBlend(); - RenderSystem.color4f(1, 1, 1, fade); - ms.push(); - ms.translate(x + 2, y + 2, 0); - ms.scale((width - 4) / 16f, (height - 4) / 16f, 1); - icon.draw(ms, this, 0, 0); - ms.pop(); + if (flashValue > .1f) { + float sin = 0.5f + 0.5f * MathHelper.sin((AnimationTickHolder.getTicks(true) + partialTicks) / 6f); + sin *= flashValue; + Color c1 = gradientColor1; + Color c2 = gradientColor2; + Color nc1 = new Color(c1.getRed(), c1.getGreen(), c1.getBlue(), MathHelper.clamp(c1.getAlpha() + 50, 0, 255)); + Color nc2 = new Color(c2.getRed(), c2.getGreen(), c2.getBlue(), MathHelper.clamp(c2.getAlpha() + 50, 0, 255)); + gradientColor1 = ColorHelper.mixColors(c1, nc1, sin); + gradientColor2 = ColorHelper.mixColors(c2, nc2, sin); } - if (item != null) { - ms.push(); - ms.translate(0, 0, -100); - GuiGameElement.of(item) - .at(x - 2, y - 2) - .scale(1.5f) - .render(ms); - ms.pop(); - } - if (shortcut != null) - drawCenteredText(ms, Minecraft.getInstance().fontRenderer, shortcut.getBoundKeyLocalizedText(), x + width / 2 + 8, - y + height - 6, ColorHelper.applyAlpha(0xff606060, fade)); - - ms.pop(); - } - - public void runCallback(double mouseX, double mouseY) { - onClick.accept((int) mouseX, (int) mouseY); } @Override - public void onClick(double p_onClick_1_, double p_onClick_3_) { - super.onClick(p_onClick_1_, p_onClick_3_); - this.pressed = true; - } + public void renderButton(@Nonnull MatrixStack ms, int mouseX, int mouseY, float partialTicks) { + super.renderButton(ms, mouseX, mouseY, partialTicks); + float fadeValue = fade.getValue(); - @Override - public void onRelease(double p_onRelease_1_, double p_onRelease_3_) { - super.onRelease(p_onRelease_1_, p_onRelease_3_); - this.pressed = false; - } + if (fadeValue < .1f) + return; - /*public void setToolTip(String text) { - toolTip.clear(); - toolTip.add(text); - }*/ + if (shortcut != null) { + ms.translate(0, 0, z+50); + drawCenteredText(ms, Minecraft.getInstance().fontRenderer, shortcut.getBoundKeyLocalizedText(), x + width / 2 + 8, y + height - 6, ColorHelper.applyAlpha(Theme.i(Theme.Key.TEXT_DARKER), fadeValue)); + } + } public ItemStack getItem() { return item; } - - @Override - public boolean isMouseOver(double x, double y) { - double m = 4; - x = Math.floor(x); - y = Math.floor(y); - return active && visible - && !(x < this.x - m || x > this.x + width + m - 1 || y < this.y - m || y > this.y + height + m - 1); - } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java index 762c873c2..efc5f90f8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AnimationTickHolder.java @@ -10,20 +10,28 @@ import net.minecraft.world.IWorld; public class AnimationTickHolder { private static int ticks; + private static int paused_ticks; public static void reset() { ticks = 0; + paused_ticks = 0; } public static void tick() { if (!Minecraft.getInstance() .isGamePaused()) { ticks = (ticks + 1) % 1_728_000; // wrap around every 24 hours so we maintain enough floating point precision + } else { + paused_ticks = (paused_ticks + 1) % 1_728_000; } } public static int getTicks() { - return ticks; + return getTicks(false); + } + + public static int getTicks(boolean includePaused) { + return includePaused ? ticks + paused_ticks : ticks; } public static float getRenderTime() { diff --git a/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java b/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java index 51996fb3a..d02fb3156 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/ColorHelper.java @@ -1,7 +1,10 @@ package com.simibubi.create.foundation.utility; +import java.awt.Color; import java.util.UUID; +import javax.annotation.Nonnull; + import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.util.math.MathHelper; @@ -39,6 +42,10 @@ public class ColorHelper { return (color & 0xFFFFFF) | alphaChannel << 24; } + public static Color applyAlpha(Color c, float alpha) { + return new Color(applyAlpha(c.getRGB(), alpha), true); + } + public static int mixColors(int color1, int color2, float w) { int r1 = (color1 >> 16); int g1 = (color1 >> 8) & 0xFF; @@ -52,6 +59,23 @@ public class ColorHelper { return color; } + @Nonnull + public static Color mixColors(@Nonnull Color c1, @Nonnull Color c2, float w) { + float[] cmp1 = c1.getRGBComponents(null); + float[] cmp2 = c2.getRGBComponents(null); + return new Color( + cmp1[0] + (cmp2[0] - cmp1[0]) * w, + cmp1[1] + (cmp2[1] - cmp1[1]) * w, + cmp1[2] + (cmp2[2] - cmp1[2]) * w, + cmp1[3] + (cmp2[3] - cmp1[3]) * w + ); + } + + @Nonnull + public static Color mixColors(@Nonnull Couple colors, float w) { + return mixColors(colors.getFirst(), colors.getSecond(), w); + } + public static int mixAlphaColors(int color1, int color2, float w) { int a1 = (color1 >> 24); int r1 = (color1 >> 16) & 0xFF; diff --git a/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java b/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java index 23e7d0080..d15b3e627 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java +++ b/src/main/java/com/simibubi/create/foundation/utility/animation/Force.java @@ -81,4 +81,22 @@ public interface Force { return timeRemaining <= 0; } } + + class Static implements Force { + float force; + + public Static(float force) { + this.force = force; + } + + @Override + public float get(float mass, float value, float speed) { + return force; + } + + @Override + public boolean finished() { + return false; + } + } } diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index 1dff79b36..6d91e2386 100644 Binary files a/src/main/resources/assets/create/textures/gui/icons.png and b/src/main/resources/assets/create/textures/gui/icons.png differ diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index 22ec3d894..7829a5f71 100644 Binary files a/src/main/resources/assets/create/textures/gui/widgets.png and b/src/main/resources/assets/create/textures/gui/widgets.png differ diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index 6e988aa5a..2ed788021 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -1,23 +1,24 @@ { - "required": true, - "priority": 1100, - "package": "com.simibubi.create.foundation.mixin", - "compatibilityLevel": "JAVA_8", - "refmap": "create.refmap.json", - "client": [ - "TileWorldHookMixin", - "CancelTileEntityRenderMixin", - "FogColorTrackerMixin", - "LightUpdateMixin", - "NetworkLightUpdateMixin", - "RenderHooksMixin", - "ShaderCloseMixin", - "TileRemoveMixin", - "EntityContraptionInteractionMixin", - "StoreProjectionMatrixMixin" - ], - "injectors": { - "defaultRequire": 1 - }, - "minVersion": "0.8" -} + "required": true, + "priority": 1100, + "package": "com.simibubi.create.foundation.mixin", + "compatibilityLevel": "JAVA_8", + "refmap": "create.refmap.json", + "client": [ + "CancelTileEntityRenderMixin", + "EntityContraptionInteractionMixin", + "FogColorTrackerMixin", + "LightUpdateMixin", + "NetworkLightUpdateMixin", + "RenderHooksMixin", + "ShaderCloseMixin", + "StoreProjectionMatrixMixin", + "TileRemoveMixin", + "TileWorldHookMixin", + "WindowResizeMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file