diff options
41 files changed, 1247 insertions, 208 deletions
diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlock.java b/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlock.java index ded6fcb..69a0640 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlock.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlock.java @@ -1,38 +1,35 @@ package io.github.cottonmc.test; -import net.fabricmc.fabric.api.block.FabricBlockSettings; -import net.fabricmc.fabric.api.container.ContainerProviderRegistry; -import net.minecraft.block.Block; -import net.minecraft.block.BlockEntityProvider; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockView; import net.minecraft.world.World; -public class GuiBlock extends Block implements BlockEntityProvider { +public class GuiBlock extends BlockWithEntity { public GuiBlock() { - super(FabricBlockSettings.copy(Blocks.IRON_BLOCK).build()); + super(FabricBlockSettings.copy(Blocks.IRON_BLOCK)); } @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hitResult) { - if (!world.isClient) { - ContainerProviderRegistry.INSTANCE.openContainer(new Identifier(LibGuiTest.MODID, "gui"), player, (buf)->buf.writeBlockPos(pos)); - } + player.openHandledScreen(state.createScreenHandlerFactory(world, pos)); return ActionResult.SUCCESS; } - @Override public BlockEntity createBlockEntity(BlockView var1) { return new GuiBlockEntity(); } + + @Override + public BlockRenderType getRenderType(BlockState state) { + return BlockRenderType.MODEL; + } } diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlockEntity.java b/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlockEntity.java index 3e76fdd..c699b47 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlockEntity.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/GuiBlockEntity.java @@ -2,10 +2,18 @@ package io.github.cottonmc.test; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.util.collection.DefaultedList; -public class GuiBlockEntity extends BlockEntity implements ImplementedInventory { +import javax.annotation.Nullable; + +public class GuiBlockEntity extends BlockEntity implements ImplementedInventory, NamedScreenHandlerFactory { DefaultedList<ItemStack> items = DefaultedList.ofSize(8, ItemStack.EMPTY); @@ -23,4 +31,14 @@ public class GuiBlockEntity extends BlockEntity implements ImplementedInventory return pos.isWithinDistance(player.getBlockPos(), 4.5); } + @Override + public Text getDisplayName() { + return new LiteralText(""); // no title + } + + @Nullable + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new TestDescription(LibGuiTest.GUI_SCREEN_HANDLER_TYPE, syncId, inv, ScreenHandlerContext.create(world, pos)); + } } diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/GuiItem.java b/GuiTest/src/main/java/io/github/cottonmc/test/GuiItem.java index b777361..699c38e 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/GuiItem.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/GuiItem.java @@ -2,6 +2,8 @@ package io.github.cottonmc.test; import io.github.cottonmc.cotton.gui.client.CottonClientScreen; import io.github.cottonmc.test.client.TestClientGui; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; @@ -21,10 +23,15 @@ public class GuiItem extends Item { @Override public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { - if (world.isClient) { - MinecraftClient.getInstance().openScreen(new CottonClientScreen(new TestClientGui())); + if (world.isClient) { + openScreen(); // In its own method to prevent class loading issues } return new TypedActionResult<ItemStack>(ActionResult.SUCCESS, (hand==Hand.MAIN_HAND) ? player.getMainHandStack() : player.getOffHandStack()); } + + @Environment(EnvType.CLIENT) + private void openScreen() { + MinecraftClient.getInstance().openScreen(new CottonClientScreen(new TestClientGui())); + } } diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java b/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java index 90f3c92..8b567b7 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/LibGuiTest.java @@ -6,16 +6,16 @@ import java.nio.file.Path; import java.util.Optional; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.container.ContainerProviderRegistry; +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; -import net.minecraft.network.PacketByteBuf; import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerType; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; @@ -25,6 +25,8 @@ public class LibGuiTest implements ModInitializer { public static GuiBlock GUI_BLOCK; public static BlockItem GUI_BLOCK_ITEM; public static BlockEntityType<GuiBlockEntity> GUI_BLOCKENTITY_TYPE; + public static ScreenHandlerType<TestDescription> GUI_SCREEN_HANDLER_TYPE; + @Override public void onInitialize() { Registry.register(Registry.ITEM, new Identifier(MODID, "client_gui"), new GuiItem()); @@ -36,11 +38,10 @@ public class LibGuiTest implements ModInitializer { GUI_BLOCKENTITY_TYPE = BlockEntityType.Builder.create(GuiBlockEntity::new, GUI_BLOCK).build(null); Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier(MODID, "gui"), GUI_BLOCKENTITY_TYPE); - - ContainerProviderRegistry.INSTANCE.registerFactory(new Identifier(MODID, "gui"), (int syncId, Identifier identifier, PlayerEntity player, PacketByteBuf buf)->{ - return new TestDescription(syncId, player.inventory, ScreenHandlerContext.create(player.getEntityWorld(), buf.readBlockPos())); + GUI_SCREEN_HANDLER_TYPE = ScreenHandlerRegistry.registerSimple(new Identifier(MODID, "gui"), (int syncId, PlayerInventory inventory) -> { + return new TestDescription(GUI_SCREEN_HANDLER_TYPE, syncId, inventory, ScreenHandlerContext.EMPTY); }); - + Optional<ModContainer> containerOpt = FabricLoader.getInstance().getModContainer("jankson"); if (containerOpt.isPresent()) { ModContainer jankson = containerOpt.get(); diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java b/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java index 3d5e48c..732494e 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/TestDescription.java @@ -4,12 +4,13 @@ import io.github.cottonmc.cotton.gui.SyncedGuiDescription; import io.github.cottonmc.cotton.gui.widget.*; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerType; import net.minecraft.text.LiteralText; public class TestDescription extends SyncedGuiDescription { - public TestDescription(int syncId, PlayerInventory playerInventory, ScreenHandlerContext context) { - super(syncId, playerInventory, getBlockInventory(context), null); + public TestDescription(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory, ScreenHandlerContext context) { + super(type, syncId, playerInventory, getBlockInventory(context), null); WGridPanel root = (WGridPanel)this.getRootPanel(); diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/client/LibGuiTestClient.java b/GuiTest/src/main/java/io/github/cottonmc/test/client/LibGuiTestClient.java index f0d3f27..5ef61c2 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/client/LibGuiTestClient.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/client/LibGuiTestClient.java @@ -4,15 +4,16 @@ import io.github.cottonmc.cotton.gui.client.CottonInventoryScreen; import io.github.cottonmc.test.LibGuiTest; import io.github.cottonmc.test.TestDescription; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry; -import net.minecraft.screen.ScreenHandlerContext; -import net.minecraft.util.Identifier; +import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; public class LibGuiTestClient implements ClientModInitializer { @Override public void onInitializeClient() { - ScreenProviderRegistry.INSTANCE.registerFactory(new Identifier(LibGuiTest.MODID, "gui"), (syncId, identifier, player, buf)->new CottonInventoryScreen<TestDescription>(new TestDescription(syncId, player.inventory, ScreenHandlerContext.create(player.getEntityWorld(), buf.readBlockPos())), player)); + ScreenRegistry.<TestDescription, CottonInventoryScreen<TestDescription>>register( + LibGuiTest.GUI_SCREEN_HANDLER_TYPE, + (desc, inventory, title) -> new CottonInventoryScreen<>(desc, inventory.player, title) + ); } } diff --git a/GuiTest/src/main/java/io/github/cottonmc/test/client/TestClientGui.java b/GuiTest/src/main/java/io/github/cottonmc/test/client/TestClientGui.java index 45426b4..bcc2584 100644 --- a/GuiTest/src/main/java/io/github/cottonmc/test/client/TestClientGui.java +++ b/GuiTest/src/main/java/io/github/cottonmc/test/client/TestClientGui.java @@ -17,7 +17,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; +import net.minecraft.text.StringRenderable; import net.minecraft.util.Identifier; public class TestClientGui extends LightweightGuiDescription { @@ -39,7 +39,7 @@ public class TestClientGui extends LightweightGuiDescription { this.setRootPanel(root); WLabel title = new WLabel(new LiteralText("Client Test Gui"), WLabel.DEFAULT_TEXT_COLOR) { @Override - public void addTooltip(List<Text> tooltip) { + public void addTooltip(List<StringRenderable> tooltip) { tooltip.add(new LiteralText("Radical!")); } }; diff --git a/gradle.properties b/gradle.properties index fc09dbd..f9f6502 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,16 +3,16 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://fabricmc.net/use - minecraft_version=1.16-pre2 - yarn_mappings=1.16-pre2+build.1 - loader_version=0.8.7+build.201 + minecraft_version=1.16.1 + yarn_mappings=1.16.1+build.20 + loader_version=0.8.8+build.202 # Mod Properties - mod_version = 2.0.0-beta.1 + mod_version = 2.2.0 maven_group = io.github.cottonmc archives_base_name = LibGui # Dependencies - fabric_version=0.11.6+build.355-1.16 + fabric_version=0.13.1+build.370-1.16 jankson_version=3.0.0+j1.2.0 modmenu_version=1.11.8+build.13 diff --git a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java index 0c31912..cf1226b 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java @@ -5,6 +5,7 @@ import javax.annotation.Nullable; import io.github.cottonmc.cotton.gui.impl.FocusHandler; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.screen.PropertyDelegate; @@ -23,8 +24,30 @@ public interface GuiDescription { public int getTitleColor(); public GuiDescription setRootPanel(WPanel panel); + + /** + * Sets the title color of this GUI. + * + * <p>The dark-mode title color will also be set by this method. + * If the specified color is {@link io.github.cottonmc.cotton.gui.widget.WLabel#DEFAULT_TEXT_COLOR}, + * the dark-mode color will be {@link io.github.cottonmc.cotton.gui.widget.WLabel#DEFAULT_DARKMODE_TEXT_COLOR}; + * otherwise it will be the specified color. + * + * @param color the new title color + * @return this GUI + */ public GuiDescription setTitleColor(int color); - + + /** + * Sets the light and dark title colors of this GUI. + * + * @param lightColor the light-mode color + * @param darkColor the dark-mode color + * @return this GUI + * @since 2.1.0 + */ + GuiDescription setTitleColor(int lightColor, int darkColor); + /** Sets the object which manages the integer properties used by WBars */ public GuiDescription setPropertyDelegate(PropertyDelegate delegate); @@ -61,4 +84,57 @@ public interface GuiDescription { default void cycleFocus(boolean lookForwards) { FocusHandler.cycleFocus(this, lookForwards); } + + /** + * Gets whether this GUI is fullscreen. + * + * <p>Fullscreen GUIs have no default background painter and + * have the root panel stretched to fit the entire screen on the client. + * + * @return true if this GUI is fullscreen, false otherwise + * @since 2.0.0 + */ + boolean isFullscreen(); + + /** + * Sets whether this GUI is fullscreen. + * + * @param fullscreen true if this GUI is fullscreen, false otherwise + * @since 2.0.0 + */ + void setFullscreen(boolean fullscreen); + + /** + * Gets whether the title of this GUI should be rendered by the screen. + * + * <p>Modders can disable this to render the title themselves with a widget. + * + * @return true if the title is visible, false otherwise + * @since 2.0.0 + */ + boolean isTitleVisible(); + + /** + * Sets whether the title of this GUI should be rendered by the screen. + * + * @param titleVisible true if the title is visible, false otherwise + * @since 2.0.0 + */ + void setTitleVisible(boolean titleVisible); + + /** + * Gets the horizontal alignment of the GUI title. + * + * @return the alignment + * @since 2.1.0 + */ + HorizontalAlignment getTitleAlignment(); + + /** + * Sets the horizontal alignment of the GUI title. + * + * @param alignment the new alignment + * @since 2.1.0 + */ + void setTitleAlignment(HorizontalAlignment alignment); } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java index 5f2bef0..cd47af4 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java @@ -1,12 +1,14 @@ package io.github.cottonmc.cotton.gui; import java.util.ArrayList; +import java.util.function.Supplier; import javax.annotation.Nullable; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.widget.*; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.block.Block; @@ -16,6 +18,7 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; import net.minecraft.item.ItemStack; import net.minecraft.screen.*; import net.minecraft.screen.slot.Slot; @@ -35,19 +38,22 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio protected WPanel rootPanel = new WGridPanel(); protected int titleColor = WLabel.DEFAULT_TEXT_COLOR; protected int darkTitleColor = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; - + protected boolean fullscreen = false; + protected boolean titleVisible = true; + protected HorizontalAlignment titleAlignment = HorizontalAlignment.LEFT; + protected WWidget focus; - - public SyncedGuiDescription(int syncId, PlayerInventory playerInventory) { - super(null, syncId); + + public SyncedGuiDescription(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory) { + super(type, syncId); this.blockInventory = null; this.playerInventory = playerInventory; this.world = playerInventory.player.world; this.propertyDelegate = null;//new ArrayPropertyDelegate(1); } - public SyncedGuiDescription(int syncId, PlayerInventory playerInventory, Inventory blockInventory, PropertyDelegate propertyDelegate) { - super(null, syncId); + public SyncedGuiDescription(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory, Inventory blockInventory, PropertyDelegate propertyDelegate) { + super(type, syncId); this.blockInventory = blockInventory; this.playerInventory = playerInventory; this.world = playerInventory.player.world; @@ -60,22 +66,31 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio } public int getTitleColor() { - return LibGuiClient.config.darkMode ? darkTitleColor : titleColor; + return (world.isClient && LibGuiClient.config.darkMode) ? darkTitleColor : titleColor; } public SyncedGuiDescription setRootPanel(WPanel panel) { this.rootPanel = panel; return this; } - + + @Override public SyncedGuiDescription setTitleColor(int color) { this.titleColor = color; + this.darkTitleColor = (color == WLabel.DEFAULT_TEXT_COLOR) ? WLabel.DEFAULT_DARKMODE_TEXT_COLOR : color; + return this; + } + + @Override + public SyncedGuiDescription setTitleColor(int lightColor, int darkColor) { + this.titleColor = lightColor; + this.darkTitleColor = darkColor; return this; } @Environment(EnvType.CLIENT) public void addPainters() { - if (this.rootPanel!=null) { + if (this.rootPanel!=null && !fullscreen) { this.rootPanel.setBackgroundPainter(BackgroundPainter.VANILLA); } } @@ -373,17 +388,43 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio * @return the found inventory */ public static Inventory getBlockInventory(ScreenHandlerContext ctx) { + return getBlockInventory(ctx, () -> EmptyInventory.INSTANCE); + } + + /** + * Gets the block inventory at the context. + * + * <p>If no inventory is found, returns a simple mutable inventory + * with the specified number of slots. + * + * <p>Searches for these implementations in the following order: + * <ol> + * <li>Blocks implementing {@code InventoryProvider}</li> + * <li>Block entities implementing {@code InventoryProvider}</li> + * <li>Block entities implementing {@code Inventory}</li> + * </ol> + * + * @param ctx the context + * @param size the fallback inventory size + * @return the found inventory + * @since 2.0.0 + */ + public static Inventory getBlockInventory(ScreenHandlerContext ctx, int size) { + return getBlockInventory(ctx, () -> new SimpleInventory(size)); + } + + private static Inventory getBlockInventory(ScreenHandlerContext ctx, Supplier<Inventory> fallback) { return ctx.run((world, pos) -> { BlockState state = world.getBlockState(pos); Block b = state.getBlock(); - + if (b instanceof InventoryProvider) { Inventory inventory = ((InventoryProvider)b).getInventory(state, world, pos); if (inventory != null) { return inventory; } } - + BlockEntity be = world.getBlockEntity(pos); if (be!=null) { if (be instanceof InventoryProvider) { @@ -395,9 +436,9 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio return (Inventory)be; } } - - return EmptyInventory.INSTANCE; - }).orElse(EmptyInventory.INSTANCE); + + return fallback.get(); + }).orElseGet(fallback); } /** @@ -420,6 +461,30 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio return new ArrayPropertyDelegate(0); }).orElse(new ArrayPropertyDelegate(0)); } + + /** + * Gets the property delegate at the context. + * + * <p>If no property delegate is found, returns an array property delegate + * with the specified number of properties. + * + * <p>Searches for block entities implementing {@link PropertyDelegateHolder}. + * + * @param ctx the context + * @param size the number of properties + * @return the found property delegate + * @since 2.0.0 + */ + public static PropertyDelegate getBlockPropertyDelegate(ScreenHandlerContext ctx, int size) { + return ctx.run((world, pos) -> { + BlockEntity be = world.getBlockEntity(pos); + if (be!=null && be instanceof PropertyDelegateHolder) { + return ((PropertyDelegateHolder)be).getPropertyDelegate(); + } + + return new ArrayPropertyDelegate(size); + }).orElse(new ArrayPropertyDelegate(size)); + } //extends ScreenHandler { @Override @@ -455,4 +520,34 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio widget.onFocusLost(); } } + + @Override + public boolean isFullscreen() { + return fullscreen; + } + + @Override + public void setFullscreen(boolean fullscreen) { + this.fullscreen = fullscreen; + } + + @Override + public boolean isTitleVisible() { + return titleVisible; + } + + @Override + public void setTitleVisible(boolean titleVisible) { + this.titleVisible = titleVisible; + } + + @Override + public HorizontalAlignment getTitleAlignment() { + return titleAlignment; + } + + @Override + public void setTitleAlignment(HorizontalAlignment titleAlignment) { + this.titleAlignment = titleAlignment; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/ValidatedSlot.java b/src/main/java/io/github/cottonmc/cotton/gui/ValidatedSlot.java index 1e9ee3c..6e7db9c 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/ValidatedSlot.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/ValidatedSlot.java @@ -7,11 +7,14 @@ import net.minecraft.screen.slot.Slot; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.function.Predicate; + public class ValidatedSlot extends Slot { private static final Logger LOGGER = LogManager.getLogger(); private final int slotNumber; private boolean insertingAllowed = true; private boolean takingAllowed = true; + private Predicate<ItemStack> filter; public ValidatedSlot(Inventory inventory, int index, int x, int y) { super(inventory, index, x, y); @@ -21,7 +24,7 @@ public class ValidatedSlot extends Slot { @Override public boolean canInsert(ItemStack stack) { - return insertingAllowed && inventory.isValid(slotNumber, stack); + return insertingAllowed && inventory.isValid(slotNumber, stack) && filter.test(stack); } @Override @@ -88,4 +91,24 @@ public class ValidatedSlot extends Slot { public void setTakingAllowed(boolean takingAllowed) { this.takingAllowed = takingAllowed; } + + /** + * Gets the item stack filter of this slot. + * + * @return the item filter + * @since 2.0.0 + */ + public Predicate<ItemStack> getFilter() { + return filter; + } + + /** + * Sets the item stack filter of this slot. + * + * @param filter the new item filter + * @since 2.0.0 + */ + public void setFilter(Predicate<ItemStack> filter) { + this.filter = filter; + } }
\ No newline at end of file diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java index 2229424..95702a6 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java @@ -10,14 +10,27 @@ import net.minecraft.text.Text; import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.lwjgl.opengl.GL11; public class CottonClientScreen extends Screen implements TextHoverRendererScreen { protected GuiDescription description; protected int left = 0; protected int top = 0; - protected int containerWidth = 0; - protected int containerHeight = 0; - + + /** + * The X coordinate of the screen title. + * + * @since 2.0.0 + */ + protected int titleX; + + /** + * The Y coordinate of the screen title. + * + * @since 2.0.0 + */ + protected int titleY; + protected WWidget lastResponder = null; public CottonClientScreen(GuiDescription description) { @@ -33,7 +46,6 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree public GuiDescription getDescription() { return description; } - @Override public void init(MinecraftClient client, int screenWidth, int screenHeight) { @@ -43,32 +55,53 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree description.addPainters(); reposition(screenWidth, screenHeight); } - - public void reposition(int screenWidth, int screenHeight) { + + /** + * Repositions the root panel. + * + * @param screenWidth the width of the screen + * @param screenHeight the height of the screen + */ + protected void reposition(int screenWidth, int screenHeight) { if (description!=null) { WPanel root = description.getRootPanel(); if (root!=null) { - this.containerWidth = root.getWidth(); - this.containerHeight = root.getHeight(); - - this.left = (screenWidth - root.getWidth()) / 2; - this.top = (screenHeight - root.getHeight()) / 2; + if (!description.isFullscreen()) { + this.left = (screenWidth - root.getWidth()) / 2; + this.top = (screenHeight - root.getHeight()) / 2; + this.titleX = 0; + this.titleY = 0; + } else { + this.left = 0; + this.top = 0; + + // Offset the title coordinates a little from the edge + this.titleX = 10; + this.titleY = 10; + + root.setSize(screenWidth, screenHeight); + } } } } - public void paint(MatrixStack matrices, int mouseX, int mouseY) { + private void paint(MatrixStack matrices, int mouseX, int mouseY) { super.renderBackground(matrices); if (description!=null) { WPanel root = description.getRootPanel(); if (root!=null) { + GL11.glEnable(GL11.GL_SCISSOR_TEST); + Scissors.refreshScissors(); root.paint(matrices, left, top, mouseX-left, mouseY-top); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + Scissors.checkStackIsEmpty(); + } + + if (getTitle() != null && description.isTitleVisible()) { + int width = description.getRootPanel().getWidth(); + ScreenDrawing.drawString(matrices, getTitle(), description.getTitleAlignment(), left + titleX, top + titleY, width, description.getTitleColor()); } - } - - if (getTitle() != null) { - textRenderer.draw(matrices, getTitle(), left, top, description.getTitleColor()); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java index 10ff4f6..4b7a726 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java @@ -13,6 +13,7 @@ import org.lwjgl.glfw.GLFW; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.lwjgl.opengl.GL11; /** * A screen for a {@link SyncedGuiDescription}. @@ -65,12 +66,26 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl description.addPainters(); - reposition(); + reposition(screenWidth, screenHeight); } - - public void reposition() { + + /** + * Clears the heavyweight peers of this screen's GUI description. + */ + private void clearPeers() { + description.slots.clear(); + } + + /** + * Repositions the root panel. + * + * @param screenWidth the width of the screen + * @param screenHeight the height of the screen + */ + protected void reposition(int screenWidth, int screenHeight) { WPanel basePanel = description.getRootPanel(); if (basePanel!=null) { + clearPeers(); basePanel.validate(description); backgroundWidth = basePanel.getWidth(); @@ -80,13 +95,24 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl if (backgroundWidth<16) backgroundWidth=300; if (backgroundHeight<16) backgroundHeight=300; } - x = (width / 2) - (backgroundWidth / 2); - y = (height / 2) - (backgroundHeight / 2); - } - - @Override - public void onClose() { - super.onClose(); + + if (!description.isFullscreen()) { + x = (width / 2) - (backgroundWidth / 2); + y = (height / 2) - (backgroundHeight / 2); + titleX = 0; + titleY = 0; + } else { + x = 0; + y = 0; + + // Offset the title coordinates a little from the edge + titleX = 10; + titleY = 10; + + if (basePanel != null) { + basePanel.setSize(screenWidth, screenHeight); + } + } } @Override @@ -211,13 +237,17 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl @Override protected void drawBackground(MatrixStack matrices, float partialTicks, int mouseX, int mouseY) {} //This is just an AbstractContainerScreen thing; most Screens don't work this way. - public void paint(MatrixStack matrices, int mouseX, int mouseY) { + private void paint(MatrixStack matrices, int mouseX, int mouseY) { super.renderBackground(matrices); if (description!=null) { WPanel root = description.getRootPanel(); if (root!=null) { + GL11.glEnable(GL11.GL_SCISSOR_TEST); + Scissors.refreshScissors(); root.paint(matrices, x, y, mouseX-x, mouseY-y); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + Scissors.checkStackIsEmpty(); } } } @@ -243,8 +273,9 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl @Override protected void drawForeground(MatrixStack matrices, int mouseX, int mouseY) { - if (description != null) { - this.textRenderer.draw(matrices, this.title, (float) this.field_25267, (float) this.field_25268, description.getTitleColor()); + if (description != null && description.isTitleVisible()) { + int width = description.getRootPanel().getWidth(); + ScreenDrawing.drawString(matrices, getTitle(), description.getTitleAlignment(), titleX, titleY, width, description.getTitleColor()); } // Don't draw the player inventory label as it's drawn by the widget itself diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java index 3eb6578..8a57551 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java @@ -1,5 +1,6 @@ package io.github.cottonmc.cotton.gui.client; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import net.minecraft.screen.PropertyDelegate; import io.github.cottonmc.cotton.gui.GuiDescription; @@ -16,10 +17,14 @@ import javax.annotation.Nullable; */ public class LightweightGuiDescription implements GuiDescription { protected WPanel rootPanel = new WGridPanel(); - protected int titleColor = WLabel.DEFAULT_TEXT_COLOR; - protected int darkmodeTitleColor = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; protected PropertyDelegate propertyDelegate; protected WWidget focus; + + protected int titleColor = WLabel.DEFAULT_TEXT_COLOR; + protected int darkmodeTitleColor = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; + protected boolean fullscreen = false; + protected boolean titleVisible = true; + protected HorizontalAlignment titleAlignment = HorizontalAlignment.LEFT; @Override public WPanel getRootPanel() { @@ -40,12 +45,20 @@ public class LightweightGuiDescription implements GuiDescription { @Override public GuiDescription setTitleColor(int color) { this.titleColor = color; + this.darkmodeTitleColor = (color == WLabel.DEFAULT_TEXT_COLOR) ? WLabel.DEFAULT_DARKMODE_TEXT_COLOR : color; + return this; + } + + @Override + public GuiDescription setTitleColor(int lightColor, int darkColor) { + this.titleColor = lightColor; + this.darkmodeTitleColor = darkColor; return this; } @Override public void addPainters() { - if (this.rootPanel!=null) { + if (this.rootPanel!=null && !fullscreen) { this.rootPanel.setBackgroundPainter(BackgroundPainter.VANILLA); } } @@ -94,4 +107,34 @@ public class LightweightGuiDescription implements GuiDescription { widget.onFocusLost(); } } + + @Override + public boolean isFullscreen() { + return fullscreen; + } + + @Override + public void setFullscreen(boolean fullscreen) { + this.fullscreen = fullscreen; + } + + @Override + public boolean isTitleVisible() { + return titleVisible; + } + + @Override + public void setTitleVisible(boolean titleVisible) { + this.titleVisible = titleVisible; + } + + @Override + public HorizontalAlignment getTitleAlignment() { + return titleAlignment; + } + + @Override + public void setTitleAlignment(HorizontalAlignment titleAlignment) { + this.titleAlignment = titleAlignment; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/Scissors.java b/src/main/java/io/github/cottonmc/cotton/gui/client/Scissors.java new file mode 100644 index 0000000..4998a05 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/Scissors.java @@ -0,0 +1,147 @@ +package io.github.cottonmc.cotton.gui.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayDeque; +import java.util.stream.Collectors; + +/** + * Contains a stack for GL scissors for restricting the drawn area of a widget. + * + * @since 2.0.0 + */ +@Environment(EnvType.CLIENT) +public final class Scissors { + private static final ArrayDeque<Frame> STACK = new ArrayDeque<>(); + + private Scissors() { + } + + /** + * Pushes a new scissor frame onto the stack and refreshes the scissored area. + * + * @param x the frame's X coordinate + * @param y the frame's Y coordinate + * @param width the frame's width in pixels + * @param height the frame's height in pixels + * @return the pushed frame + */ + public static Frame push(int x, int y, int width, int height) { + Frame frame = new Frame(x, y, width, height); + STACK.push(frame); + refreshScissors(); + + return frame; + } + + /** + * Pops the topmost scissor frame and refreshes the scissored area. + * + * @throws IllegalStateException if there are no scissor frames on the stack + */ + public static void pop() { + if (STACK.isEmpty()) { + throw new IllegalStateException("No scissors on the stack!"); + } + + STACK.pop(); + refreshScissors(); + } + + static void refreshScissors() { + MinecraftClient mc = MinecraftClient.getInstance(); + + if (STACK.isEmpty()) { + // Just use the full window framebuffer as a scissor + GL11.glScissor(0, 0, mc.getWindow().getFramebufferWidth(), mc.getWindow().getFramebufferHeight()); + return; + } + + int x = Integer.MIN_VALUE; + int y = Integer.MIN_VALUE; + int width = -1; + int height = -1; + + for (Frame frame : STACK) { + if (x < frame.x) { + x = frame.x; + } + if (y < frame.y) { + y = frame.y; + } + if (width == -1 || x + width > frame.x + frame.width) { + width = frame.width - (x - frame.x); + } + if (height == -1 || y + height > frame.y + frame.height) { + height = frame.height - (y - frame.y); + } + } + + int windowHeight = mc.getWindow().getHeight(); + double scale = mc.getWindow().getScaleFactor(); + int scaledWidth = (int) (width * scale); + int scaledHeight = (int) (height * scale); + + // Expression for Y coordinate adapted from vini2003's Spinnery (code snippet released under WTFPL) + GL11.glScissor((int) (x * scale), (int) (windowHeight - (y * scale) - scaledHeight), scaledWidth, scaledHeight); + } + + /** + * Internal method. Throws an {@link IllegalStateException} if the scissor stack is not empty. + */ + static void checkStackIsEmpty() { + if (!STACK.isEmpty()) { + throw new IllegalStateException("Unpopped scissor frames: " + STACK.stream().map(Frame::toString).collect(Collectors.joining(", "))); + } + } + + /** + * A single scissor frame in the stack. + */ + public static final class Frame implements AutoCloseable { + private final int x; + private final int y; + private final int width; + private final int height; + + private Frame(int x, int y, int width, int height) { + if (width < 0) throw new IllegalArgumentException("Negative width for a stack frame"); + if (height < 0) throw new IllegalArgumentException("Negative height for a stack frame"); + + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + /** + * Pops this frame from the stack. + * + * @throws IllegalStateException if: <ul> + * <li>this frame is not on the stack, or</li> + * <li>this frame is not the topmost element on the stack</li> + * </ul> + * @see Scissors#pop() + */ + @Override + public void close() { + if (STACK.peekLast() != this) { + if (STACK.contains(this)) { + throw new IllegalStateException(this + " is not on top of the stack!"); + } else { + throw new IllegalStateException(this + " is not on the stack!"); + } + } + + pop(); + } + + @Override + public String toString() { + return "Frame{ at = (" + x + ", " + y + "), size = (" + width + ", " + height + ") }"; + } + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java b/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java index adfff0c..07d4417 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java @@ -2,16 +2,16 @@ package io.github.cottonmc.cotton.gui.client; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.class_5348; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.StringRenderable; import net.minecraft.util.Identifier; import org.lwjgl.opengl.GL11; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; /** * {@code ScreenDrawing} contains utility methods for drawing contents on a screen. @@ -41,12 +41,9 @@ public class ScreenDrawing { * @param width the width of the box on-screen * @param height the height of the box on-screen * @param texture the Identifier for the texture - * @param u1 the left edge of the texture - * @param v1 the top edge of the texture - * @param u2 the right edge of the texture - * @param v2 the bottom edge of the texture * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint * @param opacity opacity of the drawn texture. (0f is fully opaque and 1f is fully visible) + * @since 2.0.0 */ public static void texturedRect(int x, int y, int width, int height, Identifier texture, int color, float opacity) { texturedRect(x, y, width, height, texture, 0, 0, 1, 1, color, opacity); @@ -84,6 +81,7 @@ public class ScreenDrawing { * @param v2 the bottom edge of the texture * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint * @param opacity opacity of the drawn texture. (0f is fully opaque and 1f is fully visible) + * @since 2.0.0 */ public static void texturedRect(int x, int y, int width, int height, Identifier texture, float u1, float v1, float u2, float v2, int color, float opacity) { MinecraftClient.getInstance().getTextureManager().bindTexture(texture); @@ -329,7 +327,7 @@ public class ScreenDrawing { * @param width the width of the string, used for aligning * @param color the text color */ - public static void drawString(MatrixStack matrices, String s, Alignment align, int x, int y, int width, int color) { + public static void drawString(MatrixStack matrices, String s, HorizontalAlignment align, int x, int y, int width, int color) { switch(align) { case LEFT: { MinecraftClient.getInstance().textRenderer.draw(matrices, s, x, y, color); @@ -362,7 +360,7 @@ public class ScreenDrawing { * @param color the text color * @since 1.9.0 */ - public static void drawString(MatrixStack matrices, class_5348 text, Alignment align, int x, int y, int width, int color) { + public static void drawString(MatrixStack matrices, StringRenderable text, HorizontalAlignment align, int x, int y, int width, int color) { switch(align) { case LEFT: { MinecraftClient.getInstance().textRenderer.draw(matrices, text, x, y, color); @@ -394,7 +392,7 @@ public class ScreenDrawing { * @param width the width of the string, used for aligning * @param color the text color */ - public static void drawStringWithShadow(MatrixStack matrices, String s, Alignment align, int x, int y, int width, int color) { + public static void drawStringWithShadow(MatrixStack matrices, String s, HorizontalAlignment align, int x, int y, int width, int color) { switch(align) { case LEFT: { MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, s, x, y, color); @@ -426,7 +424,7 @@ public class ScreenDrawing { * @param width the width of the string, used for aligning * @param color the text color */ - public static void drawStringWithShadow(MatrixStack matrices, class_5348 text, Alignment align, int x, int y, int width, int color) { + public static void drawStringWithShadow(MatrixStack matrices, StringRenderable text, HorizontalAlignment align, int x, int y, int width, int color) { switch(align) { case LEFT: { MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, text, x, y, color); @@ -469,7 +467,7 @@ public class ScreenDrawing { * @param y the Y position * @param color the text color */ - public static void drawString(MatrixStack matrices, class_5348 text, int x, int y, int color) { + public static void drawString(MatrixStack matrices, StringRenderable text, int x, int y, int color) { MinecraftClient.getInstance().textRenderer.draw(matrices, text, x, y, color); } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java index 1a440e9..a7f6027 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java @@ -72,7 +72,7 @@ public abstract class WAbstractSlider extends WWidget { this.max = max; this.axis = axis; this.value = min; - this.direction = (axis == Axis.HORIZONTAL) ? Direction.LEFT : Direction.UP; + this.direction = (axis == Axis.HORIZONTAL) ? Direction.RIGHT : Direction.UP; } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java index 999effc..09b87fd 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java @@ -5,6 +5,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.PropertyDelegate; import net.minecraft.text.LiteralText; +import net.minecraft.text.StringRenderable; import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; import net.minecraft.util.Identifier; @@ -162,7 +163,7 @@ public class WBar extends WWidget { } @Override - public void addTooltip(List<Text> information) { + public void addTooltip(List<StringRenderable> information) { if (tooltipLabel!=null) { int value = (field>=0) ? properties.get(field) : 0; int valMax = (max>=0) ? properties.get(max) : maxValue; @@ -184,8 +185,9 @@ public class WBar extends WWidget { } @Override - public void createPeers(GuiDescription c) { - if (properties==null) properties = c.getPropertyDelegate(); + public void validate(GuiDescription host) { + super.validate(host); + if (properties==null) properties = host.getPropertyDelegate(); } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBox.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBox.java index b7fe4c2..261e2f2 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBox.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBox.java @@ -1,6 +1,8 @@ package io.github.cottonmc.cotton.gui.widget; import io.github.cottonmc.cotton.gui.widget.data.Axis; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; +import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment; import java.util.Objects; @@ -21,6 +23,20 @@ public class WBox extends WPanel { protected Axis axis; /** + * The horizontal alignment for this box's children. + * + * @since 2.1.0 + */ + protected HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT; + + /** + * The vertical alignment for this box's children. + * + * @since 2.1.0 + */ + protected VerticalAlignment verticalAlignment = VerticalAlignment.TOP; + + /** * Constructs a box. * * @param axis the box axis @@ -60,12 +76,68 @@ public class WBox extends WPanel { public void layout() { int dimension = 0; + // Set position offset from alignment along the box axis + if (axis == Axis.HORIZONTAL && horizontalAlignment != HorizontalAlignment.LEFT) { + int widgetWidth = spacing * (children.size() - 1); + for (WWidget child : children) { + widgetWidth += child.getWidth(); + } + + if (horizontalAlignment == HorizontalAlignment.CENTER) { + dimension = (getWidth() - widgetWidth) / 2; + } else { // right + dimension = getWidth() - widgetWidth; + } + } else if (verticalAlignment != VerticalAlignment.TOP) { + int widgetHeight = spacing * (children.size() - 1); + for (WWidget child : children) { + widgetHeight += child.getHeight(); + } + + if (verticalAlignment == VerticalAlignment.CENTER) { + dimension = (getHeight() - widgetHeight) / 2; + } else { // bottom + dimension = getHeight() - widgetHeight; + } + } + for (int i = 0; i < children.size(); i++) { WWidget child = children.get(i); + if (axis == Axis.HORIZONTAL) { - child.setLocation(dimension, 0); + int y; + + switch (verticalAlignment) { + case TOP: + default: + y = 0; + break; + case CENTER: + y = (getHeight() - child.getHeight()) / 2; + break; + case BOTTOM: + y = getHeight() - child.getHeight(); + break; + } + + child.setLocation(dimension, y); } else { - child.setLocation(0, dimension); + int x; + + switch (horizontalAlignment) { + case LEFT: + default: + x = 0; + break; + case CENTER: + x = (getWidth() - child.getWidth()) / 2; + break; + case RIGHT: + x = getWidth() - child.getWidth(); + break; + } + + child.setLocation(x, dimension); } if (child instanceof WPanel) ((WPanel) child).layout(); @@ -120,4 +192,50 @@ public class WBox extends WPanel { this.axis = Objects.requireNonNull(axis, "axis"); return this; } + + /** + * Gets the horizontal alignment of this box. + * + * @return the alignment + * @since 2.1.0 + */ + public HorizontalAlignment getHorizontalAlignment() { + return horizontalAlignment; + } + + /** + * Sets the horizontal alignment of this box. + * + * @param alignment the new alignment + * @return this box + * @throws NullPointerException if the alignment is null + * @since 2.1.0 + */ + public WBox setHorizontalAlignment(HorizontalAlignment alignment) { + this.horizontalAlignment = Objects.requireNonNull(alignment, "alignment"); + return this; + } + + /** + * Gets the vertical alignment of this box. + * + * @return the alignment + * @since 2.1.0 + */ + public VerticalAlignment getVerticalAlignment() { + return verticalAlignment; + } + + /** + * Sets the vertical alignment of this box. + * + * @param alignment the new alignment + * @return this box + * @throws NullPointerException if the alignment is null + * @since 2.1.0 + */ + public WBox setVerticalAlignment(VerticalAlignment alignment) { + this.verticalAlignment = Objects.requireNonNull(alignment, "alignment"); + return this; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java index 7087e00..f65b513 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java @@ -1,32 +1,66 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.widget.icon.Icon; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.class_5348; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; +import net.minecraft.text.StringRenderable; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; + +import javax.annotation.Nullable; public class WButton extends WWidget { - private class_5348 label; + private StringRenderable label; protected int color = WLabel.DEFAULT_TEXT_COLOR; protected int darkmodeColor = WLabel.DEFAULT_TEXT_COLOR; private boolean enabled = true; - protected Alignment alignment = Alignment.CENTER; - - private Runnable onClick; + protected HorizontalAlignment alignment = HorizontalAlignment.CENTER; + @Nullable private Runnable onClick; + @Nullable private Icon icon = null; + + /** + * Constructs a button with no label and no icon. + */ public WButton() { } - - public WButton(class_5348 text) { - this.label = text; + + /** + * Constructs a button with an icon. + * + * @param icon the icon + * @since 2.2.0 + */ + public WButton(Icon icon) { + this.icon = icon; + } + + /** + * Constructs a button with a label. + * + * @param label the label + */ + public WButton(StringRenderable label) { + this.label = label; + } + + /** + * Constructs a button with an icon and a label. + * + * @param icon the icon + * @param label the label + * @since 2.2.0 + */ + public WButton(Icon icon, StringRenderable label) { + this.icon = icon; + this.label = label; } @Override @@ -58,6 +92,10 @@ public class WButton extends WWidget { ScreenDrawing.texturedRect(x, y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonLeft, buttonTop, buttonLeft+buttonWidth, buttonTop+buttonHeight, 0xFFFFFFFF); ScreenDrawing.texturedRect(x+(getWidth()/2), y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonEndLeft, buttonTop, 200*px, buttonTop+buttonHeight, 0xFFFFFFFF); + + if (icon != null) { + icon.paint(matrices, x + 2, y + 2, 16); + } if (label!=null) { int color = 0xE0E0E0; @@ -66,8 +104,9 @@ public class WButton extends WWidget { } /*else if (hovered) { color = 0xFFFFA0; }*/ - - ScreenDrawing.drawStringWithShadow(matrices, label, alignment, x, y + ((20 - 8) / 2), width, color); //LibGuiClient.config.darkMode ? darkmodeColor : color); + + int xOffset = (icon != null && alignment == HorizontalAlignment.LEFT) ? 18 : 0; + ScreenDrawing.drawStringWithShadow(matrices, label, alignment, x + xOffset, y + ((20 - 8) / 2), width, color); //LibGuiClient.config.darkMode ? darkmodeColor : color); } } @@ -96,8 +135,25 @@ public class WButton extends WWidget { } } - public WButton setOnClick(Runnable r) { - this.onClick = r; + /** + * Gets the click handler of this button. + * + * @return the click handler + * @since 2.2.0 + */ + @Nullable + public Runnable getOnClick() { + return onClick; + } + + /** + * Sets the click handler of this button. + * + * @param onClick the new click handler + * @return this button + */ + public WButton setOnClick(@Nullable Runnable onClick) { + this.onClick = onClick; return this; } @@ -110,21 +166,44 @@ public class WButton extends WWidget { return this; } - public class_5348 getLabel() { + public StringRenderable getLabel() { return label; } - public WButton setLabel(class_5348 label) { + public WButton setLabel(StringRenderable label) { this.label = label; return this; } - public Alignment getAlignment() { + public HorizontalAlignment getAlignment() { return alignment; } - public WButton setAlignment(Alignment alignment) { + public WButton setAlignment(HorizontalAlignment alignment) { this.alignment = alignment; return this; } + + /** + * Gets the icon of this button. + * + * @return the icon + * @since 2.2.0 + */ + @Nullable + public Icon getIcon() { + return icon; + } + + /** + * Sets the icon of this button. + * + * @param icon the new icon + * @return this button + * @since 2.2.0 + */ + public WButton setIcon(@Nullable Icon icon) { + this.icon = icon; + return this; + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java index d4cd9f5..531ae85 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java @@ -1,8 +1,7 @@ package io.github.cottonmc.cotton.gui.widget; -import net.minecraft.client.MinecraftClient; +import io.github.cottonmc.cotton.gui.client.Scissors; import net.minecraft.client.util.math.MatrixStack; -import org.lwjgl.opengl.GL11; /** * A panel that is clipped to only render widgets inside its bounds. @@ -12,20 +11,10 @@ public class WClippedPanel extends WPanel { public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (getBackgroundPainter()!=null) getBackgroundPainter().paintBackground(x, y, this); - GL11.glEnable(GL11.GL_SCISSOR_TEST); - MinecraftClient mc = MinecraftClient.getInstance(); - int rawHeight = mc.getWindow().getHeight(); - double scaleFactor = mc.getWindow().getScaleFactor(); - int scaledWidth = (int) (getWidth() * scaleFactor); - int scaledHeight = (int) (getHeight() * scaleFactor); - - // Expression for Y coordinate adapted from vini2003's Spinnery (code snippet released under WTFPL) - GL11.glScissor((int) (x * scaleFactor), (int) (rawHeight - (y * scaleFactor) - scaledHeight), scaledWidth, scaledHeight); - + Scissors.push(x, y, width, height); for(WWidget child : children) { child.paint(matrices, x + child.getX(), y + child.getY(), mouseX-child.getX(), mouseY-child.getY()); } - - GL11.glDisable(GL11.GL_SCISSOR_TEST); + Scissors.pop(); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java index 9e87174..a3adac9 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java @@ -4,7 +4,7 @@ import net.minecraft.client.util.math.MatrixStack; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import java.util.function.Supplier; @@ -17,7 +17,7 @@ import java.util.function.Supplier; */ public class WDynamicLabel extends WWidget { protected Supplier<String> text; - protected Alignment alignment = Alignment.LEFT; + protected HorizontalAlignment alignment = HorizontalAlignment.LEFT; protected int color; protected int darkmodeColor; @@ -71,7 +71,7 @@ public class WDynamicLabel extends WWidget { return this; } - public WDynamicLabel setAlignment(Alignment align) { + public WDynamicLabel setAlignment(HorizontalAlignment align) { this.alignment = align; return this; } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java index ffba2c3..1269afe 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItem.java @@ -62,7 +62,7 @@ public class WItem extends WWidget { MinecraftClient mc = MinecraftClient.getInstance(); ItemRenderer renderer = mc.getItemRenderer(); renderer.zOffset = 100f; - renderer.method_27951(mc.player, items.get(current), x + getWidth() / 2 - 9, y + getHeight() / 2 - 9); + renderer.renderInGui(items.get(current), x + getWidth() / 2 - 9, y + getHeight() / 2 - 9); renderer.zOffset = 0f; } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java index ec1bf9c..2aee0e7 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java @@ -2,6 +2,7 @@ package io.github.cottonmc.cotton.gui.widget; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.ValidatedSlot; @@ -11,16 +12,19 @@ import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.slot.SlotActionType; import javax.annotation.Nullable; public class WItemSlot extends WWidget { + private static final Predicate<ItemStack> DEFAULT_FILTER = stack -> true; private final List<ValidatedSlot> peers = new ArrayList<>(); @Nullable @Environment(EnvType.CLIENT) - private BackgroundPainter backgroundPainter = BackgroundPainter.SLOT; + // TODO: Set the background painter to SLOT in a new method that sets a widget's default painter. + private BackgroundPainter backgroundPainter = null; private Inventory inventory; private int startIndex = 0; private int slotsWide = 1; @@ -29,6 +33,7 @@ public class WItemSlot extends WWidget { private boolean insertingAllowed = true; private boolean takingAllowed = true; private int focusedSlot = -1; + private Predicate<ItemStack> filter = DEFAULT_FILTER; public WItemSlot(Inventory inventory, int startIndex, int slotsWide, int slotsHigh, boolean big) { this.inventory = inventory; @@ -186,8 +191,8 @@ public class WItemSlot extends WWidget { } @Override - public void createPeers(GuiDescription c) { - super.createPeers(c); + public void validate(GuiDescription host) { + super.validate(host); peers.clear(); int index = startIndex; @@ -197,8 +202,9 @@ public class WItemSlot extends WWidget { ValidatedSlot slot = createSlotPeer(inventory, index, this.getAbsoluteX() + (x * 18) + 1, this.getAbsoluteY() + (y * 18) + 1); slot.setInsertingAllowed(insertingAllowed); slot.setTakingAllowed(takingAllowed); + slot.setFilter(filter); peers.add(slot); - c.addSlotPeer(slot); + host.addSlotPeer(slot); index++; } } @@ -251,13 +257,36 @@ public class WItemSlot extends WWidget { public void setBackgroundPainter(@Nullable BackgroundPainter painter) { this.backgroundPainter = painter; } - + + /** + * Gets the item filter of this item slot. + * + * @return the item filter + * @since 2.0.0 + */ + public Predicate<ItemStack> getFilter() { + return filter; + } + + /** + * Sets the item filter of this item slot. + * + * @param filter the new item filter + * @return this item slot + * @since 2.0.0 + */ + public WItemSlot setFilter(Predicate<ItemStack> filter) { + this.filter = filter; + for (ValidatedSlot peer : peers) { + peer.setFilter(filter); + } + return this; + } + @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - if (backgroundPainter!=null) { - backgroundPainter.paintBackground(x, y, this); - } + (backgroundPainter != null ? backgroundPainter : BackgroundPainter.SLOT).paintBackground(x, y, this); } @Nullable diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java index 518a4a6..ffd8433 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java @@ -1,18 +1,20 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.class_5348; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.LiteralText; +import net.minecraft.text.StringRenderable; import net.minecraft.text.Style; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.client.TextHoverRendererScreen; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import javax.annotation.Nullable; @@ -20,8 +22,9 @@ import javax.annotation.Nullable; * A single-line label widget. */ public class WLabel extends WWidget { - protected class_5348 text; - protected Alignment alignment = Alignment.LEFT; + protected StringRenderable text; + protected HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT; + protected VerticalAlignment verticalAlignment = VerticalAlignment.TOP; protected int color; protected int darkmodeColor; @@ -51,7 +54,7 @@ public class WLabel extends WWidget { * @param text the text of the label * @param color the color of the label */ - public WLabel(class_5348 text, int color) { + public WLabel(StringRenderable text, int color) { this.text = text; this.color = color; this.darkmodeColor = (color==DEFAULT_TEXT_COLOR) ? DEFAULT_DARKMODE_TEXT_COLOR : color; @@ -72,13 +75,30 @@ public class WLabel extends WWidget { * @param text the text of the label * @since 1.8.0 */ - public WLabel(class_5348 text) { + public WLabel(StringRenderable text) { this(text, DEFAULT_TEXT_COLOR); } @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - ScreenDrawing.drawString(matrices, text, alignment, x, y, this.getWidth(), LibGuiClient.config.darkMode ? darkmodeColor : color); + MinecraftClient mc = MinecraftClient.getInstance(); + TextRenderer renderer = mc.textRenderer; + int yOffset; + + switch (verticalAlignment) { + case CENTER: + yOffset = height / 2 - renderer.fontHeight / 2; + break; + case BOTTOM: + yOffset = height - renderer.fontHeight; + break; + case TOP: + default: + yOffset = 0; + break; + } + + ScreenDrawing.drawString(matrices, text, horizontalAlignment, x, y + yOffset, this.getWidth(), LibGuiClient.config.darkMode ? darkmodeColor : color); Style hoveredTextStyle = getTextStyleAt(mouseX, mouseY); if (hoveredTextStyle != null) { @@ -196,7 +216,7 @@ public class WLabel extends WWidget { * * @return the text */ - public class_5348 getText() { + public StringRenderable getText() { return text; } @@ -206,29 +226,50 @@ public class WLabel extends WWidget { * @param text the new text * @return this label */ - public WLabel setText(class_5348 text) { + public WLabel setText(StringRenderable text) { this.text = text; return this; } /** - * Gets the text alignment of this label. + * Gets the horizontal text alignment of this label. + * + * @return the alignment + * @since 2.0.0 + */ + public HorizontalAlignment getHorizontalAlignment() { + return horizontalAlignment; + } + + /** + * Sets the horizontal text alignment of this label. + * + * @param align the new text alignment + * @return this label + */ + public WLabel setHorizontalAlignment(HorizontalAlignment align) { + this.horizontalAlignment = align; + return this; + } + + /** + * Gets the vertical text alignment of this label. * * @return the alignment * @since 2.0.0 */ - public Alignment getAlignment() { - return alignment; + public VerticalAlignment getVerticalAlignment() { + return verticalAlignment; } /** - * Sets the text alignment of this label. + * Sets the vertical text alignment of this label. * * @param align the new text alignment * @return this label */ - public WLabel setAlignment(Alignment align) { - this.alignment = align; + public WLabel setVerticalAlignment(VerticalAlignment align) { + this.verticalAlignment = align; return this; } }
\ No newline at end of file diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java index 7f122da..200b191 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java @@ -2,14 +2,14 @@ package io.github.cottonmc.cotton.gui.widget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.class_5348; import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.Vector3f; +import net.minecraft.text.StringRenderable; import net.minecraft.util.math.Quaternion; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import io.github.cottonmc.cotton.gui.widget.data.Axis; import javax.annotation.Nullable; @@ -26,9 +26,9 @@ import javax.annotation.Nullable; public class WLabeledSlider extends WAbstractSlider { private static final Quaternion ROTATION_Z_270 = Vector3f.POSITIVE_X.getDegreesQuaternion(270); - @Nullable private class_5348 label = null; + @Nullable private StringRenderable label = null; @Nullable private LabelUpdater labelUpdater = null; - private Alignment labelAlignment = Alignment.CENTER; + private HorizontalAlignment labelAlignment = HorizontalAlignment.CENTER; /** * Constructs a horizontal slider with no default label. @@ -59,7 +59,7 @@ public class WLabeledSlider extends WAbstractSlider { * @param axis the slider axis * @param label the slider label (can be null) */ - public WLabeledSlider(int min, int max, Axis axis, @Nullable class_5348 label) { + public WLabeledSlider(int min, int max, Axis axis, @Nullable StringRenderable label) { this(min, max, axis); this.label = label; } @@ -71,7 +71,7 @@ public class WLabeledSlider extends WAbstractSlider { * @param max the maximum value * @param label the slider label (can be null) */ - public WLabeledSlider(int min, int max, @Nullable class_5348 label) { + public WLabeledSlider(int min, int max, @Nullable StringRenderable label) { this(min, max); this.label = label; } @@ -91,7 +91,7 @@ public class WLabeledSlider extends WAbstractSlider { * @return the label */ @Nullable - public class_5348 getLabel() { + public StringRenderable getLabel() { return label; } @@ -100,7 +100,7 @@ public class WLabeledSlider extends WAbstractSlider { * * @param label the new label */ - public void setLabel(@Nullable class_5348 label) { + public void setLabel(@Nullable StringRenderable label) { this.label = label; } @@ -117,7 +117,7 @@ public class WLabeledSlider extends WAbstractSlider { * * @return the alignment */ - public Alignment getLabelAlignment() { + public HorizontalAlignment getLabelAlignment() { return labelAlignment; } @@ -126,7 +126,7 @@ public class WLabeledSlider extends WAbstractSlider { * * @param labelAlignment the new alignment */ - public void setLabelAlignment(Alignment labelAlignment) { + public void setLabelAlignment(HorizontalAlignment labelAlignment) { this.labelAlignment = labelAlignment; } @@ -228,6 +228,6 @@ public class WLabeledSlider extends WAbstractSlider { * @param value the slider value * @return the label */ - class_5348 updateLabel(int value); + StringRenderable updateLabel(int value); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WListPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WListPanel.java index 9ba8562..bcfbf2b 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WListPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WListPanel.java @@ -97,8 +97,9 @@ public class WListPanel<D, W extends WWidget> extends WClippedPanel { child.setParent(this); // Set up the widget's host if (host != null) { - child.validate(host); - child.createPeers(host); + // setHost instead of validate since we cannot have independent validations + // TODO: System for independently validating widgets? + child.setHost(host); } return child; } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java index d657a01..10725ee 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java @@ -27,6 +27,7 @@ public abstract class WPanel extends WWidget { @Environment(EnvType.CLIENT) private BackgroundPainter backgroundPainter = null; + @SuppressWarnings("deprecation") @Override public void createPeers(GuiDescription c) { super.createPeers(c); @@ -174,8 +175,16 @@ public abstract class WPanel extends WWidget { return this; } + /** + * {@inheritDoc} + * + * <p>Subclasses should call {@code super.validate(c)} to ensure that children are validated. + * + * @param c the host GUI description + */ @Override public void validate(GuiDescription c) { + super.validate(c); layout(); for (WWidget child : children) { child.validate(c); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPlayerInvPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPlayerInvPanel.java index da2ac1c..3879e1f 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPlayerInvPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPlayerInvPanel.java @@ -1,5 +1,6 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -13,6 +14,8 @@ import javax.annotation.Nullable; public class WPlayerInvPanel extends WPlainPanel { private final WItemSlot inv; private final WItemSlot hotbar; + @Nullable + private final WWidget label; /** * Constructs a player inventory panel with a label. @@ -44,6 +47,7 @@ public class WPlayerInvPanel extends WPlainPanel { public WPlayerInvPanel(PlayerInventory playerInventory, @Nullable WWidget label) { int y = 0; + this.label = label; if (label != null) { this.add(label, 0, 0, label.getWidth(), label.getHeight()); y += label.getHeight(); @@ -75,5 +79,12 @@ public class WPlayerInvPanel extends WPlainPanel { hotbar.setBackgroundPainter(painter); return this; } -} + @Override + public void validate(GuiDescription c) { + super.validate(c); + if (c != null && label instanceof WLabel) { + ((WLabel) label).setColor(c.getTitleColor()); + } + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java index 4cf268e..8fb50b8 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java @@ -1,18 +1,19 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.class_5348; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.StringRenderable; import net.minecraft.text.Style; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.client.TextHoverRendererScreen; -import io.github.cottonmc.cotton.gui.widget.data.Alignment; +import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import javax.annotation.Nullable; import java.util.List; @@ -24,18 +25,19 @@ import java.util.Objects; * @since 1.8.0 */ public class WText extends WWidget { - protected class_5348 text; + protected StringRenderable text; protected int color; protected int darkmodeColor; - protected Alignment alignment = Alignment.LEFT; - private List<class_5348> wrappedLines; + protected HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT; + protected VerticalAlignment verticalAlignment = VerticalAlignment.TOP; + private List<StringRenderable> wrappedLines; private boolean wrappingScheduled = false; - public WText(class_5348 text) { + public WText(StringRenderable text) { this(text, WLabel.DEFAULT_TEXT_COLOR); } - public WText(class_5348 text, int color) { + public WText(StringRenderable text, int color) { this.text = Objects.requireNonNull(text, "text must not be null"); this.color = color; this.darkmodeColor = (color == WLabel.DEFAULT_TEXT_COLOR) ? WLabel.DEFAULT_DARKMODE_TEXT_COLOR : color; @@ -72,7 +74,7 @@ public class WText extends WWidget { int lineIndex = y / font.fontHeight; if (lineIndex >= 0 && lineIndex < wrappedLines.size()) { - class_5348 line = wrappedLines.get(lineIndex); + StringRenderable line = wrappedLines.get(lineIndex); return font.getTextHandler().trimToWidth(line, x); } @@ -88,11 +90,26 @@ public class WText extends WWidget { } TextRenderer font = MinecraftClient.getInstance().textRenderer; + + int yOffset; + switch (verticalAlignment) { + case CENTER: + yOffset = height / 2 - font.fontHeight * wrappedLines.size() / 2; + break; + case BOTTOM: + yOffset = height - font.fontHeight * wrappedLines.size(); + break; + case TOP: + default: + yOffset = 0; + break; + } + for (int i = 0; i < wrappedLines.size(); i++) { - class_5348 line = wrappedLines.get(i); + StringRenderable line = wrappedLines.get(i); int c = LibGuiClient.config.darkMode ? darkmodeColor : color; - ScreenDrawing.drawString(matrices, line, alignment, x, y + i * font.fontHeight, width, c); + ScreenDrawing.drawString(matrices, line, horizontalAlignment, x, y + yOffset + i * font.fontHeight, width, c); } Style hoveredTextStyle = getTextStyleAt(mouseX, mouseY); @@ -120,7 +137,7 @@ public class WText extends WWidget { * * @return the text */ - public class_5348 getText() { + public StringRenderable getText() { return text; } @@ -130,7 +147,7 @@ public class WText extends WWidget { * @param text the new text * @return this label */ - public WText setText(class_5348 text) { + public WText setText(StringRenderable text) { Objects.requireNonNull(text, "text is null"); this.text = text; wrappingScheduled = true; @@ -203,24 +220,46 @@ public class WText extends WWidget { } /** - * Gets the alignment of this text widget. + * Gets the horizontal alignment of this text widget. * * @return the alignment * @since 1.9.0 */ - public Alignment getAlignment() { - return alignment; + public HorizontalAlignment getHorizontalAlignment() { + return horizontalAlignment; } /** - * Sets the alignment of this text widget. + * Sets the horizontal alignment of this text widget. * - * @param alignment the new alignment + * @param horizontalAlignment the new alignment * @return this widget * @since 1.9.0 */ - public WText setAlignment(Alignment alignment) { - this.alignment = alignment; + public WText setHorizontalAlignment(HorizontalAlignment horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + return this; + } + + /** + * Gets the vertical alignment of this text widget. + * + * @return the alignment + * @since 2.0.0 + */ + public VerticalAlignment getVerticalAlignment() { + return verticalAlignment; + } + + /** + * Sets the vertical alignment of this text widget. + * + * @param verticalAlignment the new alignment + * @return this widget + * @since 2.0.0 + */ + public WText setVerticalAlignment(VerticalAlignment verticalAlignment) { + this.verticalAlignment = verticalAlignment; return this; } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java index d49074f..516c876 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java @@ -52,6 +52,50 @@ public class WTiledSprite extends WSprite { tileHeight = height; } + /** + * Gets the tile width of this sprite. + * + * @return the tile width + * @since 2.2.0 + */ + public int getTileWidth() { + return tileWidth; + } + + /** + * Gets the tile height of this sprite. + * + * @return the tile height + * @since 2.2.0 + */ + public int getTileHeight() { + return tileHeight; + } + + /** + * Sets the tile width of this sprite. + * + * @param tileWidth the new tile width + * @return this sprite + * @since 2.2.0 + */ + public WTiledSprite setTileWidth(int tileWidth) { + this.tileWidth = tileWidth; + return this; + } + + /** + * Sets the tile height of this sprite. + * + * @param tileHeight the new tile height + * @return this sprite + * @since 2.2.0 + */ + public WTiledSprite setTileHeight(int tileHeight) { + this.tileHeight = tileHeight; + return this; + } + @Environment(EnvType.CLIENT) @Override public void paintFrame(int x, int y, Identifier texture) { @@ -65,7 +109,7 @@ public class WTiledSprite extends WSprite { x + tileXOffset, y + tileYOffset, // but using the set tileWidth and tileHeight instead of the full height and // width - tileWidth, tileHeight, + getTileWidth(), getTileHeight(), // render the current texture texture, // clips the texture if wanted diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java index 9d1306f..b917d97 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java @@ -2,11 +2,11 @@ package io.github.cottonmc.cotton.gui.widget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.class_5348; import net.minecraft.client.MinecraftClient; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; +import net.minecraft.text.StringRenderable; import net.minecraft.util.Identifier; import io.github.cottonmc.cotton.gui.client.LibGuiClient; @@ -25,7 +25,7 @@ public class WToggleButton extends WWidget { protected Identifier offImage; protected Identifier focusImage = DEFAULT_FOCUS_IMAGE; - @Nullable protected class_5348 label = null; + @Nullable protected StringRenderable label = null; protected boolean isOn = false; @Nullable protected Consumer<Boolean> onToggle = null; @@ -39,7 +39,7 @@ public class WToggleButton extends WWidget { } /** Defaults with text */ - public WToggleButton(class_5348 text) { + public WToggleButton(StringRenderable text) { this(DEFAULT_ON_IMAGE, DEFAULT_OFF_IMAGE); this.label = text; } @@ -51,7 +51,7 @@ public class WToggleButton extends WWidget { } /** Custom images, with default sizes and a label */ - public WToggleButton(Identifier onImage, Identifier offImage, class_5348 label) { + public WToggleButton(Identifier onImage, Identifier offImage, StringRenderable label) { this.onImage = onImage; this.offImage = offImage; this.label = label; @@ -118,11 +118,11 @@ public class WToggleButton extends WWidget { } @Nullable - public class_5348 getLabel() { + public StringRenderable getLabel() { return label; } - public WToggleButton setLabel(@Nullable class_5348 label) { + public WToggleButton setLabel(@Nullable StringRenderable label) { this.label = label; return this; } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java index 7476c71..e615c53 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java @@ -9,7 +9,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; +import net.minecraft.text.StringRenderable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -310,9 +310,10 @@ public class WWidget { /** * Creates "heavyweight" component peers * @param c the top-level Container that will hold the peers + * @deprecated All widget peers should be added in {@link #validate(GuiDescription)}. */ + @Deprecated public void createPeers(GuiDescription c) { - host=c; } /** @@ -348,7 +349,7 @@ public class WWidget { */ @Environment(EnvType.CLIENT) public void renderTooltip(MatrixStack matrices, int x, int y, int tX, int tY) { - List<Text> info = new ArrayList<>(); + List<StringRenderable> info = new ArrayList<>(); addTooltip(info); if (info.size() == 0) @@ -361,16 +362,41 @@ public class WWidget { /** * Creates component peers, lays out children, and initializes animation data for this Widget and all its children. * The host container must clear any heavyweight peers from its records before this method is called. + * + * @param host the host GUI description */ public void validate(GuiDescription host) { - //valid = true; + this.host = host; + } + + /** + * Gets the host of this widget. + * + * @return the host + * @see #host + * @since 2.1.0 + */ + @Nullable + public final GuiDescription getHost() { + return host; + } + + /** + * Sets the host of this widget without creating peers. + * + * @param host the new host + * @see #host + * @since 2.1.0 + */ + public void setHost(@Nullable GuiDescription host) { + this.host = host; } /** * Adds lines to this widget's tooltip. If the lines remain empty after this call, no tooltip will be drawn. * @param tooltip List containing all previous tooltip data. */ - public void addTooltip(List<Text> tooltip) { + public void addTooltip(List<StringRenderable> tooltip) { } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Color.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Color.java index 9ed9d38..9b78ae9 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Color.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Color.java @@ -176,6 +176,23 @@ public interface Color { float c = getChroma()/255f; return c / (1 - Math.abs(2*l - 1)); } + + /** + * Calculates an interpolated value along the fraction t between 0.0 and 1.0. When t = 1.0, endVal is returned. + * Eg.: If this color is black, your endColor is white and t = 0.5 you get gray. + * + * @param endColor a Color to interpolate with + * @param t fraction between 0.0 and 1.0 + * + * @since 2.0.0 + */ + public RGB interpolate(RGB endColor, double t){ + double a = (endColor.getA() - this.getA()) * t + this.getA(); + double r = (endColor.getR() - this.getR()) * t + this.getR(); + double g = (endColor.getG() - this.getG()) * t + this.getG(); + double b = (endColor.getB() - this.getB()) * t + this.getB(); + return new RGB((int)a, (int)r, (int)g, (int)b); + } } public static class HSL implements Color { diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Alignment.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/HorizontalAlignment.java index 3e3420a..61c914d 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Alignment.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/HorizontalAlignment.java @@ -1,6 +1,6 @@ package io.github.cottonmc.cotton.gui.widget.data; -public enum Alignment { +public enum HorizontalAlignment { LEFT, CENTER, RIGHT; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/VerticalAlignment.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/VerticalAlignment.java new file mode 100644 index 0000000..8123ad3 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/VerticalAlignment.java @@ -0,0 +1,7 @@ +package io.github.cottonmc.cotton.gui.widget.data; + +public enum VerticalAlignment { + TOP, + CENTER, + BOTTOM; +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/Icon.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/Icon.java new file mode 100644 index 0000000..ccf1bcc --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/Icon.java @@ -0,0 +1,25 @@ +package io.github.cottonmc.cotton.gui.widget.icon; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.util.math.MatrixStack; + +/** + * A square icon for a widget such as a button. + * + * @see ItemIcon + * @see TextureIcon + * @since 2.2.0 + */ +public interface Icon { + /** + * Paints this icon. + * + * @param matrices the GUI matrix stack + * @param x the X coordinate + * @param y the Y coordinate + * @param size the size of this icon in pixels (size N means a N*N square) + */ + @Environment(EnvType.CLIENT) + void paint(MatrixStack matrices, int x, int y, int size); +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/ItemIcon.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/ItemIcon.java new file mode 100644 index 0000000..3ce8eaa --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/ItemIcon.java @@ -0,0 +1,42 @@ +package io.github.cottonmc.cotton.gui.widget.icon; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; + +/** + * An icon that draws an item stack. + * + * @since 2.2.0 + */ +public class ItemIcon implements Icon { + private final ItemStack stack; + + /** + * Constructs an item icon. + * + * @param stack the drawn item stack + */ + public ItemIcon(ItemStack stack) { + this.stack = stack; + } + + @Environment(EnvType.CLIENT) + @Override + public void paint(MatrixStack matrices, int x, int y, int size) { + MinecraftClient client = MinecraftClient.getInstance(); + ItemRenderer renderer = client.getItemRenderer(); + + float scale = size != 16 ? ((float) size / 16f) : 1f; + + RenderSystem.pushMatrix(); + RenderSystem.translatef(x, y, 0); + RenderSystem.scalef(scale, scale, 1); + renderer.renderInGui(stack, 0, 0); + RenderSystem.popMatrix(); + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java new file mode 100644 index 0000000..0876cb5 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java @@ -0,0 +1,73 @@ +package io.github.cottonmc.cotton.gui.widget.icon; + +import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; + +/** + * An icon that draws a texture. + * + * @since 2.2.0 + */ +public class TextureIcon implements Icon { + private final Identifier texture; + private float opacity = 1f; + private int color = 0xFF_FFFFFF; + + /** + * Constructs a new texture icon. + * + * @param texture the identifier of the icon texture + */ + public TextureIcon(Identifier texture) { + this.texture = texture; + } + + /** + * Gets the opacity of the texture. + * + * @return the opacity + */ + public float getOpacity() { + return opacity; + } + + /** + * Sets the opacity of the texture. + * + * @param opacity the new opacity between 0 (fully transparent) and 1 (fully opaque) + * @return this icon + */ + public TextureIcon setOpacity(float opacity) { + this.opacity = opacity; + return this; + } + + /** + * Gets the color tint of the texture. + * + * @return the color tint + */ + public int getColor() { + return color; + } + + /** + * Sets the color tint of the texture. + * + * @param color the new color tint + * @return this icon + */ + public TextureIcon setColor(int color) { + this.color = color; + return this; + } + + @Environment(EnvType.CLIENT) + @Override + public void paint(MatrixStack matrices, int x, int y, int size) { + ScreenDrawing.texturedRect(x, y, size, size, texture, color, opacity); + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/package-info.java new file mode 100644 index 0000000..54bbc92 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/package-info.java @@ -0,0 +1,14 @@ +/** + * The icon API for displaying various icons on widgets. + * + * <p>For example, you can attach an icon to a button: + * <pre> + * {@code + * // This is a button with an apple item as the icon: + * WButton button = new WButton(new ItemIcon(new ItemStack(Items.APPLE)), new LiteralText("Apple button")); + * } + * </pre> + * + * @since 2.2.0 + */ +package io.github.cottonmc.cotton.gui.widget.icon; diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index d194e9e..22d9990 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -6,7 +6,8 @@ "name": "LibGui", "description": "Easy grid-based GUIs for Fabric", "authors": [ - "Falkreon" + "Falkreon", + "Juuz" ], "contact": { "sources": "https://github.com/CottonMC/LibGUI" @@ -21,9 +22,10 @@ "modmenu": ["io.github.cottonmc.cotton.gui.client.modmenu.ModMenuSupport"] }, "depends": { - "fabricloader": ">=0.4.0", + "fabricloader": ">=0.8.8", "fabric": "*", - "minecraft": ">=1.16-" + "minecraft": ">=1.16.1", + "jankson": "^3.0.0" }, "suggests": { "flamingo": "*" |