From 349cbb7de19cb72679db5cdd02394722ab95c44b Mon Sep 17 00:00:00 2001 From: brachy84 Date: Sun, 8 Oct 2023 15:02:32 +0200 Subject: [PATCH 1/7] start --- docs/mod-wiki/modularui/getting_started.md | 23 ++++++++++++++++ docs/mod-wiki/modularui/intro.md | 32 ++++++++++++++++++++++ mkdocs.yml | 4 +++ 3 files changed, 59 insertions(+) create mode 100644 docs/mod-wiki/modularui/getting_started.md create mode 100644 docs/mod-wiki/modularui/intro.md diff --git a/docs/mod-wiki/modularui/getting_started.md b/docs/mod-wiki/modularui/getting_started.md new file mode 100644 index 0000000..24cefbe --- /dev/null +++ b/docs/mod-wiki/modularui/getting_started.md @@ -0,0 +1,23 @@ +# Getting Started + +## Adding ModularUI to your mod +Add the maven to the repositories (if not already present) +````groovy +maven { + name 'CurseMaven' + url 'https://cursemaven.com' + content { + includeGroup 'curse.maven' + } +} +```` +and the dependency declaration to dependencies +````groovy +implementation 'curse.maven:modularui-624243:4786372-sources-4786373' +```` + +- `624243` is the Curseforge project id of ModularUI +- `4779301` is the `dev` file id (for version 2.2.3) +- `4779302` is the `sources` file id (for version 2.2.3) + +Make sure to use the latest version! \ No newline at end of file diff --git a/docs/mod-wiki/modularui/intro.md b/docs/mod-wiki/modularui/intro.md new file mode 100644 index 0000000..0900427 --- /dev/null +++ b/docs/mod-wiki/modularui/intro.md @@ -0,0 +1,32 @@ +# ModularUI + +## What is ModularUI? +ModularUI is a library for Minecraft aiming to make GUI's much easier. + +### History +- First appearance of ModularUI in GTCE by Archengius +- on 30th December 2021 GTCEu released with some improvements to its GUI library +- on 16th January 2022 Rongmario created the ModularUI repository in the CleanroomMC organization with the intention to rewrite it +- on 19th February I (brachy) started working on ModularUI +- on 21st May 2022 ModularUI version 1.0.0 was released on Curseforge +- miozune decided to port ModularUI to 1.7.10 for GTNH +- after 3 month of updates I decided to rewrite some parts of the library +- the rewrite turned very large and thus ModularUI 2 was born +- on 21st March 2023 I uploaded version 2.0.0 to Curseforge +- since then ModularUI is constantly receiving updates + +## Why ModularUI? +Minecrafts (and Forges) gui code is not very good and the code gets really messy really fast. With ModularUI you can build +GUIs fast by adding Widgets to panels with layout widgets, so you don't have to calculate positions and sizes yourself. +ModularUI is very dynamic and allows for very complicated client only or even client-server synced GUIs. +A good example is fluid slots in GUIs. Minecraft and Forge don't offer anything to add fluid slots or tanks to a GUI. +With ModularUI you simply call `.child(new FluidSlot().syncHandler(new FluidTank(16000)))` (along with some setters). + +## Key features +- panel system similar to windows +- widgets are placed in a tree like structure +- widget rendering and interactions are automatically handled +- syncing widget values +- good for client only GUIs and client-server synced GUIs +- GUI themes are loaded via JSON and can be added and modified by resourcepacks +- JEI compat for things like exclusion zones diff --git a/mkdocs.yml b/mkdocs.yml index 9404f3d..942e10a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,6 +26,10 @@ nav: - Configuration: mod-development/mixin/environment/configuration.md - Rendering: - Colouring Blocks and Items: mod-development/rendering/colouring-blocks-and-items.md + - Mod Wikis: + - ModularUI: + - Intro: mod-wiki/modularui/intro.md + - Getting Started: mod-wiki/modularui/getting_started.md - Proposal: - Standard: - Minecraft Technical Metric System: proposal/standard/mtms.md From 6d1de1d39b951ce30c6dd92b47a1179a56300518 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Sun, 15 Oct 2023 12:16:45 +0200 Subject: [PATCH 2/7] more docs --- .../mod-wiki/modularui/client_gui_tutorial.md | 102 ++++++++++++ docs/mod-wiki/modularui/getting_started.md | 39 ++++- docs/mod-wiki/modularui/modularscreen.md | 0 .../mod-wiki/modularui/synced_gui_tutorial.md | 155 ++++++++++++++++++ mkdocs.yml | 2 + 5 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 docs/mod-wiki/modularui/client_gui_tutorial.md create mode 100644 docs/mod-wiki/modularui/modularscreen.md create mode 100644 docs/mod-wiki/modularui/synced_gui_tutorial.md diff --git a/docs/mod-wiki/modularui/client_gui_tutorial.md b/docs/mod-wiki/modularui/client_gui_tutorial.md new file mode 100644 index 0000000..a91a06c --- /dev/null +++ b/docs/mod-wiki/modularui/client_gui_tutorial.md @@ -0,0 +1,102 @@ +Here we want to create a UI that only exist on the client side and doesn't sync any data. + +## 1. Creating the screen +First we need a new screen class which extends `ModularScreen`. Intellij immidiatly asks us to add a constructor and to override `buildUI()`. +(You can also use the `ModularScreen` constructor where you pass in a `ModularPanel`.) +```java +public class TutorialScreen extends ModularScreen { + + // these two strings are used to identify this screen. For owner you can use the mod id and + // for name you can use anything that fits the purpose of the screen + public TutorialScreen(@NotNull String owner) { + super(owner, name); + } + + @Override + public ModularPanel buildUI(GuiContext context) { + return null; + } +} +``` + +The `buildUI` is where the fun happens. Here you must create the main `ModularPanel` and it's widget tree. This method is called from the `ModularScreen` constructor. You should NOT call it by yourself. + +Let's create a `ModularPanel`. For that you can use the normal constructor or you call `ModularPanel.default()`. You can also create a custom panel class for more customization. +The `default()` method automatically sets the size to 176 x 166 and centers it in the screen. A default background texture is given by the assigned `Theme`, but you can set your own with `.background()` if you want. +```java +public class TutorialScreen extends ModularScreen { + + // simplify constructor + public TutorialScreen() { + super("tutorial_mod"); + } + + @Override + public ModularPanel buildUI(GuiContext context) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); + // create widget tree here + return panel; + } +} +``` + +From now on we will only look at the `buildUI` method. +For now lets put a title at the top of the panel. For that we'll use `.child()` and pass a widget to it. To create a text widget we can use `IKey.str().asWidget`. (Note: You can create a translated string with `IKey.lang()`). +We also want to set the postion, for that we chain `.top()` and `.left()` on ANY widegt which implements `IPositioned`. We don't need to set a size since `TextWidget` calculates it on its own. But you can limit the width for example and the text will automatically wrap, if necessary. +```java +public ModularPanel buildUI(GuiContext context) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); + panel.child(IKey.str("My first screen").asWidget() + .top(7).left(7)); + return panel; +} +``` + +## 2. Opening the screen +We want to open the screen when the player right clicks with a diamond. We use a forge event for that and simply check for client side and a diamond. +Then we open the screen with `ClientGUI.open()`. You need to pass a screen instance from your earlier created class. +Now let's boot up minecraft and test it. + +```java +@Mod.EventBusSubscriber +public class EventHandler { + + @SubscribeEvent + public static void onItemUse(PlayerInteractEvent.RightClickItem event) { + if (event.getEntityPlayer().getEntityWorld().isRemote && event.getItemStack().getItem() == Items.DIAMOND) { + ClientGUI.open(new TutorialGui()); + } + } +} +``` +Your screen should look like this, when you take a diamond and right click. The blurry background comes from the Blur mod. It is not required, but it makes things look nicer in my opinion. +You may notice the purple text in the bottom left corner or a border on widgets when you hover them. That's the debug mode. Its enabled by default in a dev environment and can be disabled via the config file or by pressing `CTRL + SHIFT + ALT + C` while in a ModularUI screen. +![grafik](https://user-images.githubusercontent.com/45517902/228584027-eaf4f49b-1967-4aa1-9cd3-416e5610f113.png) + +## 3. Adding a button +Now let's add a button, that greets the player with a message. For that we will use the `ButtonWidget`. Here we do need to set a size since the text on the button is not a widget, but a `IDrawable`, which doesnt size itself. It uses the size of its widget. We don't need to set a background since its set by the current Theme. We center the button in the panel using `.align(Alignment.Center)` and set a size with `.size(60, 16)`. We could also use `.width(60).height(16)`. It's the same thing. +```java +public ModularPanel buildUI(GuiContext context) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); + panel.child(IKey.str("My first screen").asWidget() + .top(7).left(7)) + .child(new ButtonWidget<>() + .align(Alignment.Center) + .size(60, 16) + .overlay(IKey.str("Say Hello")) + .onMousePressed(button -> { + EntityPlayer player = Minecraft.getMinecraft().player; + player.sendMessage(new TextComponentString("Hello " + player.getName())); + return true; + })); + return panel; +} +``` +Let's see what it looks like. +![grafik](https://user-images.githubusercontent.com/45517902/228590064-108ae148-acc8-45ca-9d96-e91cbe0f2e4a.png) + +Pressing the button greets the player in the chat. +![grafik](https://user-images.githubusercontent.com/45517902/228590312-24f6bd17-dd05-44ee-96bd-6ae7d00e59cc.png) + +Simple, right? + diff --git a/docs/mod-wiki/modularui/getting_started.md b/docs/mod-wiki/modularui/getting_started.md index 24cefbe..af59ce7 100644 --- a/docs/mod-wiki/modularui/getting_started.md +++ b/docs/mod-wiki/modularui/getting_started.md @@ -1,7 +1,9 @@ # Getting Started ## Adding ModularUI to your mod + Add the maven to the repositories (if not already present) + ````groovy maven { name 'CurseMaven' @@ -11,7 +13,9 @@ maven { } } ```` + and the dependency declaration to dependencies + ````groovy implementation 'curse.maven:modularui-624243:4786372-sources-4786373' ```` @@ -20,4 +24,37 @@ implementation 'curse.maven:modularui-624243:4786372-sources-4786373' - `4779301` is the `dev` file id (for version 2.2.3) - `4779302` is the `sources` file id (for version 2.2.3) -Make sure to use the latest version! \ No newline at end of file +Make sure to use the latest version! + +## Development Tools + +I highly recommend using IntelliJ in combination with the Single Hotswap plugin. + +## Other documentation + +As always, the code itself is the best documentation. Most API classes have lots of useful javadoc information. + +## Creating a GUI + +First you need to decide if you want a client only screen or a client-server synced gui. + +### Client only GUI + +Client only GUIs are easier to work with, but they can't communicate with the server. +You can open one by calling `ClientGUI.open(ModularScreen, JeiSettings)`. +`JeiSettings` can be omitted by an overloaded method. Client only GUIs don't display jei on the side by default. +You can change that by creating your own `JeiSettings` instance. The `ModularScreen` should be a new instance. + +### Synced GUI + +Synced GUIs are much more complicated to open. The most important thing is that you must only open synced GUIs +on server side. ModularUI (via Forge) automatically syncs to client. This means you need to supply enough information on +server side to find the GUI on client side. For example if the GUI is bound to a `TileEntity`, then you need to supply +at least a world instance and a block position. `GuiInfo`s take care of that information. +Not that Forge only syncs `EntityPlayer`, `World` and a `BlockPos`. For more specific data you need multiple `GuiInfo`s. +For example if a GUI is opened on right click with an item. The `GuiInfo` does not know with wich hand the GUI was +opened. +That's why ModularUI provides two `GuiInfo`s for that. One for main hand and one for the off hand. +ModularUI provides some default `GuiInfo`s at `GuiInfos`. If you want to create your own `GuiInfo`, take a look at +`GuiInfo.builder()`. +Now that you have your `GuiInfo`, simply call `open()` with your needed parameters. diff --git a/docs/mod-wiki/modularui/modularscreen.md b/docs/mod-wiki/modularui/modularscreen.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/mod-wiki/modularui/synced_gui_tutorial.md b/docs/mod-wiki/modularui/synced_gui_tutorial.md new file mode 100644 index 0000000..cd83374 --- /dev/null +++ b/docs/mod-wiki/modularui/synced_gui_tutorial.md @@ -0,0 +1,155 @@ + +First you need to decide how you want to open the GUI. Through a right click on a block or by right clicking an item? +ModularUI has helpers for both of those cases, but you can also implement custom behaviour if that's needed. + +In this tutorial we will open a GUI on right clicking a block. +## Creating the Block +At the top we subscribe to some events to register the block and the item form. +Whats interesting for us is the method at the bottom `onBlockActivated()`. This is called when the block is right clicked. +Inside we first check if the method is called on server side. This is important. **Synced GUI's MUST be opened ONLY from server side!**. +Then we simply call `GuiInfos.TILE_ENTITY.open(playerIn, worldIn, pos);`. This will find the tile entity at the blocks position and tries to open the GUI on client and server side. +```java +public class TestBlock extends Block implements ITileEntityProvider { + + public static final Block testBlock = new TestBlock(); + public static final ItemBlock testItemBlock = new ItemBlock(testBlock); + + public static void preInit() { + ResourceLocation rl = new ResourceLocation("tutorial_mod", "test_block"); + testBlock.setRegistryName(rl); + testItemBlock.setRegistryName(rl); + GameRegistry.registerTileEntity(TestTile.class, rl); + } + + @SubscribeEvent + public static void registerBlocks(RegistryEvent.Register event) { + IForgeRegistry registry = event.getRegistry(); + registry.register(testBlock); + } + + @SubscribeEvent + public static void registerItems(RegistryEvent.Register event) { + IForgeRegistry registry = event.getRegistry(); + registry.register(testItemBlock); + } + + public TestBlock() { + super(Material.ROCK); + } + + @Nullable + @Override + public TileEntity createNewTileEntity(@NotNull World worldIn, int meta) { + return new TestTile(); + } + + @Override + public boolean onBlockActivated(World worldIn, @NotNull BlockPos pos, @NotNull IBlockState state, @NotNull EntityPlayer playerIn, @NotNull EnumHand hand, @NotNull EnumFacing facing, float hitX, float hitY, float hitZ) { + if (!worldIn.isRemote) { + GuiInfos.TILE_ENTITY.open(playerIn, worldIn, pos); + } + return true; + } +} +``` + +## Creating the TileEntity +This is fairly simple. Extend `TileEntity` and implement `IGuiHolder`. Then override `buildUI()`. You can also override `createScreen()` to create a custom screen, but most of the time you wont need that. + +Inside the `buildUI()` is where the fun stuff happens. The method is called on both client and server side, but only on client side the widgets are kept. But on both sides the syncing information is kept. +Here we currently only create a panel and attach the player inventory. **The GUI must be synced for ANY slots to work!** +```java +public class TestTile extends TileEntity implements IGuiHolder { + + @Override + public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_gui"); + panel.bindPlayerInventory(); + return panel; + } +} +``` +Our GUI now looks like this. We have a correctly positioned player inventory at the bottom. +![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/affc34c2-e89a-4f5a-9010-8ac352145cc9) +For synced GUI's JEI is enabled by default. You can change that by overriding `createScreen()` in your tile entity. +```java +@SideOnly(Side.CLIENT) +@Override +public ModularScreen createScreen(GuiCreationContext guiCreationContext, ModularPanel mainPanel) { + ModularScreen screen = IGuiHolder.super.createScreen(guiCreationContext, mainPanel); + screen.context.disableJei(); + return screen; +} +``` + +## Syncing custom values +Now let's add a progress bar to the GUI. For that we first make the tile ticking. Inside `update()` we upadte the progress variable, but only on server side to simulate a working machine (and to showcase syncing). Once the progress reaches 100 ticks it's reset to 0. 100 ticks equals 5 seconds. +```java +private int progress = 0; + +@Override +public void update() { + if (!getWorld().isRemote && this.progress++ == 100) { + this.progress = 0; + } +} +``` +Now add a progress widget to the panel. +```java +@Override +public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_gui"); + panel.bindPlayerInventory() + .child(new ProgressWidget() + .size(20) + .leftRel(0.5f).topRelAnchor(0.25f, 0.5f) + .texture(GuiTextures.PROGRESS_ARROW, 20) + .value(new DoubleSyncValue(() -> this.progress / 100.0, val -> this.progress = (int) (val * 100)))); + return panel; +} +``` +The whole syncing information is in this line: +```java +.value(new DoubleSyncValue(() -> this.progress / 100.0, val -> this.progress = (int) (val * 100)))); +``` +`value()` accepts an instance of `IDoubleValue`. If we want the value to be synced we need to use `DoubleSyncValue`. The constructor needs to arguments. A getter as `DoubleSupplier` and a setter as `DoubleConsumer`. The progress widget wants a double value between 0 and 1 so we need to divide by the maximum value (100). The getter is called on server side on compared by a cached value to figure out if it needs to be synced. +On client side the setter is called to update our progress field on client side. But since only the widget needs that value and nothing else we could also pass in `null` for the second argument (the DoubleSyncValue caches it's own progress value based on the passed getter). + +## Result +The progress bar takes 5 seconds to fill up and then restarts as expected. +![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/62dfbe81-0093-471a-a7f2-36c7d1808a4e) +The full tile entity: +```java +public class TestTile extends TileEntity implements IGuiHolder, ITickable { + + private int progress = 0; + + // remove this if you want jei enabled + @SideOnly(Side.CLIENT) + @Override + public ModularScreen createScreen(GuiCreationContext guiCreationContext, ModularPanel mainPanel) { + ModularScreen screen = IGuiHolder.super.createScreen(guiCreationContext, mainPanel); + screen.context.disableJei(); + return screen; + } + + @Override + public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_gui"); + panel.bindPlayerInventory() + .child(new ProgressWidget() + .size(20) + .leftRel(0.5f).topRelAnchor(0.25f, 0.5f) + .texture(GuiTextures.PROGRESS_ARROW, 20) + .value(new DoubleSyncValue(() -> this.progress / 100.0, val -> this.progress = (int) (val * 100)))); + return panel; + } + + @Override + public void update() { + if (!getWorld().isRemote && this.progress++ == 100) { + this.progress = 0; + } + } +} +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 942e10a..cb7b7d6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,6 +30,8 @@ nav: - ModularUI: - Intro: mod-wiki/modularui/intro.md - Getting Started: mod-wiki/modularui/getting_started.md + - Client GUI tutorial: mod-wiki/modularui/client_gui_tutorial.md + - Synced GUI tutorial: mod-wiki/modularui/synced_gui_tutorial.md - Proposal: - Standard: - Minecraft Technical Metric System: proposal/standard/mtms.md From a3931e744c41063056b3fff538ddeba85e5b6cb2 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Sun, 15 Oct 2023 22:26:41 +0200 Subject: [PATCH 3/7] fixes --- .../mod-wiki/modularui/client_gui_tutorial.md | 94 ++++++++----------- docs/mod-wiki/modularui/intro.md | 35 +------ .../mod-wiki/modularui/synced_gui_tutorial.md | 39 +++----- 3 files changed, 54 insertions(+), 114 deletions(-) diff --git a/docs/mod-wiki/modularui/client_gui_tutorial.md b/docs/mod-wiki/modularui/client_gui_tutorial.md index a91a06c..4faa315 100644 --- a/docs/mod-wiki/modularui/client_gui_tutorial.md +++ b/docs/mod-wiki/modularui/client_gui_tutorial.md @@ -1,72 +1,52 @@ Here we want to create a UI that only exist on the client side and doesn't sync any data. -## 1. Creating the screen -First we need a new screen class which extends `ModularScreen`. Intellij immidiatly asks us to add a constructor and to override `buildUI()`. -(You can also use the `ModularScreen` constructor where you pass in a `ModularPanel`.) -```java -public class TutorialScreen extends ModularScreen { - - // these two strings are used to identify this screen. For owner you can use the mod id and - // for name you can use anything that fits the purpose of the screen - public TutorialScreen(@NotNull String owner) { - super(owner, name); - } - - @Override - public ModularPanel buildUI(GuiContext context) { - return null; - } -} -``` - -The `buildUI` is where the fun happens. Here you must create the main `ModularPanel` and it's widget tree. This method is called from the `ModularScreen` constructor. You should NOT call it by yourself. +We will make the GUI as simple as possible -Let's create a `ModularPanel`. For that you can use the normal constructor or you call `ModularPanel.default()`. You can also create a custom panel class for more customization. -The `default()` method automatically sets the size to 176 x 166 and centers it in the screen. A default background texture is given by the assigned `Theme`, but you can set your own with `.background()` if you want. -```java -public class TutorialScreen extends ModularScreen { - - // simplify constructor - public TutorialScreen() { - super("tutorial_mod"); - } - - @Override - public ModularPanel buildUI(GuiContext context) { - ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); - // create widget tree here - return panel; +## 1. Creating the screen +First create a new class with a static method, which returns a `ModularScreen`. +````java +public class TutorialGUI { + + public static ModularScreen createGUI() { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel"); + return new ModularScreen(panel); } } -``` +```` +This creates the most basic GUI with a 176 x 166 centered panel. Take a look at the constructor and method used +including their javadoc. The GUI's theme defines widgets backgrounds. By default, this gives panels the default vanilla background. +You can call `.background()` to set your own background. However, creating a new theme is recommended if applicable. -From now on we will only look at the `buildUI` method. For now lets put a title at the top of the panel. For that we'll use `.child()` and pass a widget to it. To create a text widget we can use `IKey.str().asWidget`. (Note: You can create a translated string with `IKey.lang()`). We also want to set the postion, for that we chain `.top()` and `.left()` on ANY widegt which implements `IPositioned`. We don't need to set a size since `TextWidget` calculates it on its own. But you can limit the width for example and the text will automatically wrap, if necessary. ```java -public ModularPanel buildUI(GuiContext context) { - ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); +public static ModularScreen createGUI() { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel"); panel.child(IKey.str("My first screen").asWidget() .top(7).left(7)); - return panel; + return new ModularScreen(panel); } ``` ## 2. Opening the screen We want to open the screen when the player right clicks with a diamond. We use a forge event for that and simply check for client side and a diamond. -Then we open the screen with `ClientGUI.open()`. You need to pass a screen instance from your earlier created class. +Then we open the screen with `ClientGUI.open()`. Pass in a new screen instance with the method we just created. Now let's boot up minecraft and test it. ```java @Mod.EventBusSubscriber -public class EventHandler { +public class TutorialGUI { @SubscribeEvent public static void onItemUse(PlayerInteractEvent.RightClickItem event) { if (event.getEntityPlayer().getEntityWorld().isRemote && event.getItemStack().getItem() == Items.DIAMOND) { - ClientGUI.open(new TutorialGui()); + ClientGUI.open(createGUI()); } } + + public static ModularScreen createGUI() { + ... + } } ``` Your screen should look like this, when you take a diamond and right click. The blurry background comes from the Blur mod. It is not required, but it makes things look nicer in my opinion. @@ -76,20 +56,20 @@ You may notice the purple text in the bottom left corner or a border on widgets ## 3. Adding a button Now let's add a button, that greets the player with a message. For that we will use the `ButtonWidget`. Here we do need to set a size since the text on the button is not a widget, but a `IDrawable`, which doesnt size itself. It uses the size of its widget. We don't need to set a background since its set by the current Theme. We center the button in the panel using `.align(Alignment.Center)` and set a size with `.size(60, 16)`. We could also use `.width(60).height(16)`. It's the same thing. ```java -public ModularPanel buildUI(GuiContext context) { - ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel", context); - panel.child(IKey.str("My first screen").asWidget() - .top(7).left(7)) - .child(new ButtonWidget<>() - .align(Alignment.Center) - .size(60, 16) - .overlay(IKey.str("Say Hello")) - .onMousePressed(button -> { - EntityPlayer player = Minecraft.getMinecraft().player; - player.sendMessage(new TextComponentString("Hello " + player.getName())); - return true; - })); - return panel; +public static ModularScreen createGui() { + ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel"); + panel.child(IKey.str("My first screen").asWidget() + .top(7).left(7)) + .child(new ButtonWidget<>() + .align(Alignment.Center) + .size(60, 16) + .overlay(IKey.str("Say Hello")) + .onMousePressed(button -> { + EntityPlayer player = Minecraft.getMinecraft().player; + player.sendMessage(new TextComponentString("Hello " + player.getName())); + return true; + })); + return new ModularScreen(panel); } ``` Let's see what it looks like. diff --git a/docs/mod-wiki/modularui/intro.md b/docs/mod-wiki/modularui/intro.md index 0900427..951b70a 100644 --- a/docs/mod-wiki/modularui/intro.md +++ b/docs/mod-wiki/modularui/intro.md @@ -1,32 +1,3 @@ -# ModularUI - -## What is ModularUI? -ModularUI is a library for Minecraft aiming to make GUI's much easier. - -### History -- First appearance of ModularUI in GTCE by Archengius -- on 30th December 2021 GTCEu released with some improvements to its GUI library -- on 16th January 2022 Rongmario created the ModularUI repository in the CleanroomMC organization with the intention to rewrite it -- on 19th February I (brachy) started working on ModularUI -- on 21st May 2022 ModularUI version 1.0.0 was released on Curseforge -- miozune decided to port ModularUI to 1.7.10 for GTNH -- after 3 month of updates I decided to rewrite some parts of the library -- the rewrite turned very large and thus ModularUI 2 was born -- on 21st March 2023 I uploaded version 2.0.0 to Curseforge -- since then ModularUI is constantly receiving updates - -## Why ModularUI? -Minecrafts (and Forges) gui code is not very good and the code gets really messy really fast. With ModularUI you can build -GUIs fast by adding Widgets to panels with layout widgets, so you don't have to calculate positions and sizes yourself. -ModularUI is very dynamic and allows for very complicated client only or even client-server synced GUIs. -A good example is fluid slots in GUIs. Minecraft and Forge don't offer anything to add fluid slots or tanks to a GUI. -With ModularUI you simply call `.child(new FluidSlot().syncHandler(new FluidTank(16000)))` (along with some setters). - -## Key features -- panel system similar to windows -- widgets are placed in a tree like structure -- widget rendering and interactions are automatically handled -- syncing widget values -- good for client only GUIs and client-server synced GUIs -- GUI themes are loaded via JSON and can be added and modified by resourcepacks -- JEI compat for things like exclusion zones +--8<-- +https://raw.githubusercontent.com/CleanroomMC/ModularUI/master/README.md +--8<-- diff --git a/docs/mod-wiki/modularui/synced_gui_tutorial.md b/docs/mod-wiki/modularui/synced_gui_tutorial.md index cd83374..d31881f 100644 --- a/docs/mod-wiki/modularui/synced_gui_tutorial.md +++ b/docs/mod-wiki/modularui/synced_gui_tutorial.md @@ -9,9 +9,9 @@ Whats interesting for us is the method at the bottom `onBlockActivated()`. This Inside we first check if the method is called on server side. This is important. **Synced GUI's MUST be opened ONLY from server side!**. Then we simply call `GuiInfos.TILE_ENTITY.open(playerIn, worldIn, pos);`. This will find the tile entity at the blocks position and tries to open the GUI on client and server side. ```java -public class TestBlock extends Block implements ITileEntityProvider { +public class TutorialBlock extends Block implements ITileEntityProvider { - public static final Block testBlock = new TestBlock(); + public static final Block testBlock = new TutorialBlock(); public static final ItemBlock testItemBlock = new ItemBlock(testBlock); public static void preInit() { @@ -33,7 +33,7 @@ public class TestBlock extends Block implements ITileEntityProvider { registry.register(testItemBlock); } - public TestBlock() { + public TutorialBlock() { super(Material.ROCK); } @@ -59,7 +59,7 @@ This is fairly simple. Extend `TileEntity` and implement `IGuiHolder`. Then over Inside the `buildUI()` is where the fun stuff happens. The method is called on both client and server side, but only on client side the widgets are kept. But on both sides the syncing information is kept. Here we currently only create a panel and attach the player inventory. **The GUI must be synced for ANY slots to work!** ```java -public class TestTile extends TileEntity implements IGuiHolder { +public class TutorialTile extends TileEntity implements IGuiHolder { @Override public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { @@ -71,16 +71,6 @@ public class TestTile extends TileEntity implements IGuiHolder { ``` Our GUI now looks like this. We have a correctly positioned player inventory at the bottom. ![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/affc34c2-e89a-4f5a-9010-8ac352145cc9) -For synced GUI's JEI is enabled by default. You can change that by overriding `createScreen()` in your tile entity. -```java -@SideOnly(Side.CLIENT) -@Override -public ModularScreen createScreen(GuiCreationContext guiCreationContext, ModularPanel mainPanel) { - ModularScreen screen = IGuiHolder.super.createScreen(guiCreationContext, mainPanel); - screen.context.disableJei(); - return screen; -} -``` ## Syncing custom values Now let's add a progress bar to the GUI. For that we first make the tile ticking. Inside `update()` we upadte the progress variable, but only on server side to simulate a working machine (and to showcase syncing). Once the progress reaches 100 ticks it's reset to 0. 100 ticks equals 5 seconds. @@ -97,7 +87,7 @@ public void update() { Now add a progress widget to the panel. ```java @Override -public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { +public ModularPanel buildUI(GuiCreationContext creationContext, GuiSyncManager syncManager, boolean isClient) { ModularPanel panel = ModularPanel.defaultPanel("tutorial_gui"); panel.bindPlayerInventory() .child(new ProgressWidget() @@ -115,26 +105,25 @@ The whole syncing information is in this line: `value()` accepts an instance of `IDoubleValue`. If we want the value to be synced we need to use `DoubleSyncValue`. The constructor needs to arguments. A getter as `DoubleSupplier` and a setter as `DoubleConsumer`. The progress widget wants a double value between 0 and 1 so we need to divide by the maximum value (100). The getter is called on server side on compared by a cached value to figure out if it needs to be synced. On client side the setter is called to update our progress field on client side. But since only the widget needs that value and nothing else we could also pass in `null` for the second argument (the DoubleSyncValue caches it's own progress value based on the passed getter). +You can disable JEI in your synced GUI by adding this line into your `buildUI()` method +```java +creationContext.getJeiSettings().disableJei(); +``` + ## Result The progress bar takes 5 seconds to fill up and then restarts as expected. ![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/62dfbe81-0093-471a-a7f2-36c7d1808a4e) The full tile entity: ```java -public class TestTile extends TileEntity implements IGuiHolder, ITickable { +public class TutorialTile extends TileEntity implements IGuiHolder, ITickable { private int progress = 0; - // remove this if you want jei enabled - @SideOnly(Side.CLIENT) @Override - public ModularScreen createScreen(GuiCreationContext guiCreationContext, ModularPanel mainPanel) { - ModularScreen screen = IGuiHolder.super.createScreen(guiCreationContext, mainPanel); - screen.context.disableJei(); - return screen; - } + public ModularPanel buildUI(GuiCreationContext creationContext, GuiSyncManager syncManager, boolean isClient) { + // disables jei + creationContext.getJeiSettings().disableJei(); - @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, boolean isClient) { ModularPanel panel = ModularPanel.defaultPanel("tutorial_gui"); panel.bindPlayerInventory() .child(new ProgressWidget() From fb65a74823b4e1f2e144632baa51f64cffd0ffb2 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Mon, 16 Oct 2023 12:45:31 +0200 Subject: [PATCH 4/7] even more docs --- docs/mod-wiki/modularui/anchor.png | Bin 0 -> 20710 bytes .../mod-wiki/modularui/client_gui_tutorial.md | 30 ++++-- docs/mod-wiki/modularui/framework.md | 62 ++++++++++++ docs/mod-wiki/modularui/getting_started.md | 8 ++ docs/mod-wiki/modularui/modularscreen.md | 0 .../modularui/sizing_and_positioning.md | 89 ++++++++++++++++++ .../mod-wiki/modularui/synced_gui_tutorial.md | 27 ++++-- mkdocs.yml | 2 + 8 files changed, 199 insertions(+), 19 deletions(-) create mode 100644 docs/mod-wiki/modularui/anchor.png create mode 100644 docs/mod-wiki/modularui/framework.md delete mode 100644 docs/mod-wiki/modularui/modularscreen.md create mode 100644 docs/mod-wiki/modularui/sizing_and_positioning.md diff --git a/docs/mod-wiki/modularui/anchor.png b/docs/mod-wiki/modularui/anchor.png new file mode 100644 index 0000000000000000000000000000000000000000..35a8d5e89ce4022596a190c14c641601c9f51472 GIT binary patch literal 20710 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 literal 0 HcmV?d00001 diff --git a/docs/mod-wiki/modularui/client_gui_tutorial.md b/docs/mod-wiki/modularui/client_gui_tutorial.md index 4faa315..251ce32 100644 --- a/docs/mod-wiki/modularui/client_gui_tutorial.md +++ b/docs/mod-wiki/modularui/client_gui_tutorial.md @@ -14,11 +14,15 @@ public class TutorialGUI { } ```` This creates the most basic GUI with a 176 x 166 centered panel. Take a look at the constructor and method used -including their javadoc. The GUI's theme defines widgets backgrounds. By default, this gives panels the default vanilla background. -You can call `.background()` to set your own background. However, creating a new theme is recommended if applicable. +including their javadoc. The GUI's theme defines widgets backgrounds. By default, this gives panels the default vanilla +background. You can call `.background()` to set your own background. However, creating a new theme is recommended if +applicable. -For now lets put a title at the top of the panel. For that we'll use `.child()` and pass a widget to it. To create a text widget we can use `IKey.str().asWidget`. (Note: You can create a translated string with `IKey.lang()`). -We also want to set the postion, for that we chain `.top()` and `.left()` on ANY widegt which implements `IPositioned`. We don't need to set a size since `TextWidget` calculates it on its own. But you can limit the width for example and the text will automatically wrap, if necessary. +For now lets put a title at the top of the panel. For that we'll use `.child()` and pass a widget to it. To create a +text widget we can use `IKey.str().asWidget`. (Note: You can create a translated string with `IKey.lang()`). We also +want to set the postion, for that we chain `.top()` and `.left()` on ANY widegt which implements `IPositioned`. We don't +need to set a size since `TextWidget` calculates it on its own. But you can limit the width for example and the text +will automatically wrap, if necessary. ```java public static ModularScreen createGUI() { ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel"); @@ -29,9 +33,9 @@ public static ModularScreen createGUI() { ``` ## 2. Opening the screen -We want to open the screen when the player right clicks with a diamond. We use a forge event for that and simply check for client side and a diamond. -Then we open the screen with `ClientGUI.open()`. Pass in a new screen instance with the method we just created. -Now let's boot up minecraft and test it. +We want to open the screen when the player right clicks with a diamond. We use a forge event for that and simply check +for client side and a diamond. Then we open the screen with `ClientGUI.open()`. Pass in a new screen instance with the +method we just created. Now let's boot up minecraft and test it. ```java @Mod.EventBusSubscriber @@ -49,12 +53,18 @@ public class TutorialGUI { } } ``` -Your screen should look like this, when you take a diamond and right click. The blurry background comes from the Blur mod. It is not required, but it makes things look nicer in my opinion. -You may notice the purple text in the bottom left corner or a border on widgets when you hover them. That's the debug mode. Its enabled by default in a dev environment and can be disabled via the config file or by pressing `CTRL + SHIFT + ALT + C` while in a ModularUI screen. +Your screen should look like this, when you take a diamond and right click. The blurry background comes from the Blur +mod. It is not required, but it makes things look nicer in my opinion. You may notice the purple text in the bottom left +corner or a border on widgets when you hover them. That's the debug mode. Its enabled by default in a dev environment +and can be disabled via the config file or by pressing `CTRL + SHIFT + ALT + C` while in a ModularUI screen. ![grafik](https://user-images.githubusercontent.com/45517902/228584027-eaf4f49b-1967-4aa1-9cd3-416e5610f113.png) ## 3. Adding a button -Now let's add a button, that greets the player with a message. For that we will use the `ButtonWidget`. Here we do need to set a size since the text on the button is not a widget, but a `IDrawable`, which doesnt size itself. It uses the size of its widget. We don't need to set a background since its set by the current Theme. We center the button in the panel using `.align(Alignment.Center)` and set a size with `.size(60, 16)`. We could also use `.width(60).height(16)`. It's the same thing. +Now let's add a button, that greets the player with a message. For that we will use the `ButtonWidget`. Here we do need +to set a size since the text on the button is not a widget, but a `IDrawable`, which doesnt size itself. It uses the +size of its widget. We don't need to set a background since its set by the current Theme. We center the button in the +panel using `.align(Alignment.Center)` and set a size with `.size(60, 16)`. We could also use `.width(60).height(16)`. +It's the same thing. ```java public static ModularScreen createGui() { ModularPanel panel = ModularPanel.defaultPanel("tutorial_panel"); diff --git a/docs/mod-wiki/modularui/framework.md b/docs/mod-wiki/modularui/framework.md new file mode 100644 index 0000000..c8147c7 --- /dev/null +++ b/docs/mod-wiki/modularui/framework.md @@ -0,0 +1,62 @@ +This page is about some core classes of a Modular GUI. + +## ModularScreen + +This is the core of each GUI on the client side. It keeps track of all panels. +This is where the `GuiContext` is stored. + +Useful methods are: + +- `getOwner()` returns the owner of the screen (usually a mod id) +- `getName()` returns the name of the main panel +- `getContext()` returns the `GuiContext` +- `getWindowManager()` returns the `WindowManager` +- `getSyncManager()` returns the `GuiSyncManager` +- `isClientOnly()` returns if the screen is only open on client side +- `registerGuiActionListener()` register an interaction listener +- `registerFrameUpdateListener()` registers a listener which is called approximately 60 times per second +- `getCurrentTheme()` returns the active theme for the screen +- `useTheme()` tries to set the new theme (does nothing if theme is overridden by resource packs) + +## GuiContext + +This class keeps track of the current GUI state. For example pressed buttons and keys, focused widgets +dragging widgets, mouse position, JEI settings, themes and most importantly viewports and transformations. + +Useful methods are: + +- `isAbove()` returns if the mouse is above a widget +- all methods related to hovering +- all methods related to focusing +- `hasDraggable()` if the mouse is currently dragging an `IDraggable` (not including item stacks) +- `isMouseItemEmpty()` if the mouse is currently not dragging an `ItemStack` +- `getMouseX()` and `getMouseY()` returns the current mouse position with the current transformations applied to it. + That + means it is relative to the current widgets position +- `getMouseAbsX()` and `getMouseAbsY()` returns the true (absolute) mouse position +- `unTransformMouseX()` and `unTransformMouseY()` is like `getMouseX()` and `getMouseY()`, but the transformations are + inverted +- `getMouseButton()` returns the last pressed mouse button +- `getMouseWheel()` returns the last scroll wheel use +- `getKeyCode()` returns the last typed key code +- `getTypedChar()` returns the last typed character +- `getPartialTicks()` returns the partial ticks for the current frame +- `getTheme()` returns the current active theme +- `getJeiSettings()` returns the current modifiable JEI settings + +## ModularPanel + +This is the root of each widget tree. Panels are also [widgets](#widget). + +## Widget + +A widget is an element in the widget tree. It has a size and position and it can be rendered on screen. + +This class has a lot of useful methods, too many to list them all. But you can take a look yourself. I did my best +to structure it and make it clean. + +## WindowManager +Keeps track of all panels and the main panels. Handles opening and closing panels + +## GuiSyncManager +Manages sync values. This is the only class (with `ModularContainer`) that exists on client and server side. diff --git a/docs/mod-wiki/modularui/getting_started.md b/docs/mod-wiki/modularui/getting_started.md index af59ce7..66cb6e5 100644 --- a/docs/mod-wiki/modularui/getting_started.md +++ b/docs/mod-wiki/modularui/getting_started.md @@ -24,6 +24,8 @@ implementation 'curse.maven:modularui-624243:4786372-sources-4786373' - `4779301` is the `dev` file id (for version 2.2.3) - `4779302` is the `sources` file id (for version 2.2.3) +By including the sources in your dependency declaration you'll get access to the real uncompiled code with javadocs. + Make sure to use the latest version! ## Development Tools @@ -45,6 +47,10 @@ You can open one by calling `ClientGUI.open(ModularScreen, JeiSettings)`. `JeiSettings` can be omitted by an overloaded method. Client only GUIs don't display jei on the side by default. You can change that by creating your own `JeiSettings` instance. The `ModularScreen` should be a new instance. +Go [here](client_gui_tutorial.md) to get started on creating a client GUI. Even if you are looking into making a synced +GUI, I still recommend +checking it out as it contains some information which is useful for both cases. + ### Synced GUI Synced GUIs are much more complicated to open. The most important thing is that you must only open synced GUIs @@ -58,3 +64,5 @@ That's why ModularUI provides two `GuiInfo`s for that. One for main hand and one ModularUI provides some default `GuiInfo`s at `GuiInfos`. If you want to create your own `GuiInfo`, take a look at `GuiInfo.builder()`. Now that you have your `GuiInfo`, simply call `open()` with your needed parameters. + +Go [here](synced_gui_tutorial.md) to get started on creating a synced GUI. diff --git a/docs/mod-wiki/modularui/modularscreen.md b/docs/mod-wiki/modularui/modularscreen.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/mod-wiki/modularui/sizing_and_positioning.md b/docs/mod-wiki/modularui/sizing_and_positioning.md new file mode 100644 index 0000000..3c1a042 --- /dev/null +++ b/docs/mod-wiki/modularui/sizing_and_positioning.md @@ -0,0 +1,89 @@ +Each widget has several builder setter methods for position and size. They all come from the `IPositioned` interface. + +## Sizing + +- `width(int)` sets the widget width in pixels +- `widthRel(float)` sets the widget width relative to its parent (f.e. if the parent is 120 wide and we + call`widthRel(0.5f)` then our widget will be 60 wide +- `heigth(int)` and `heightRel(float)` work analogue +- `size(int width, int height)` is equivalent to `.width(width).height(height)` +- `size(int val)` is equivalent to `.width(val).height(val)` +- `sizeRel(float width, float height)` and `sizeRel(float val)` work analogue +- `coverChildrenWidth()` makes the widget width wrapping tightly around its children +- `coverChildrenHeight()` works analogue +- `coverChildren()` wraps width and height tightly +- `expanded()` is only useful for children of `Row` and `Column` widgets. It will make the widget expand as much as + possible in the widgets axis (width in row and height in column) + +## Positioning + +We can set position on four different points. Two for each axis. `left()`, `right()`, `top()` and `bottom()`. +To understand what they are doing take a look at the following picture: + +![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/ab173431-1509-414c-8db4-4545c985a9bd) + +As you can see the methods are fairly self-explanatory. Each of those methods has multiple variants much like `width()` +and `widthRel()`. Only methods for `left()` will be listed here. + +- `left(int)` sets the x position in pixels relative to its parent +- `leftRel(float)` sets the relative x position relative to its parent (f.e. 0.5f will center the widget) (it might not + be too easy to fully understand how this works right now +- `leftRelOffset(float val, int offset)` is the same as `leftRel()`, but also adds an `offset` in pixels after the + calculation +- `leftRelAnchor(float val, float anchor)` is the same as `leftRel()`, but with a different anchor + (see [Anchor](#anchor)) +- `leftRel(float val, int offset, float anchor)` combines `leftRelOffset()` and `leftRelAnchor()` +- `left(float val, int offset, float anchor, Measure measure)` is `leftRel(float val, int offset, float anchor)`, but + you can define the measure (pixels or relative yourself) (this method is mostly useless since offset and anchor are + only effective with relative measure) +- `left(DoubleSupplier val, Measure measure)` is like `left()` and `leftRel()`, but with a dynamic value. Note that the + supplier is only evaluated during resizing. You can't use for animating widgets. +- `leftRelOffset(DoubleSupplier val, int offset)` is like `leftRelOffset(float val, int offset)` with a dynamic value +- `leftRelAnchor(DoubleSupplier val, float anchor)` is like `leftRelAnchor(float val, float anchor)` with a dynamic + value +- `leftRel(DoubleSupplier val, int offset, float anchor)` combines the two methods above + +All the above variants also exist for `right()`, `top()` and `bottom()`. +Additionally, there is + +- `pos(int x, int y)` combines `left(int x)` and `top(int y)` +- `posRel(float x, floaty)` combines `leftRel(float x)` and `topRel(float y)` + +### Anchor + +The anchor is the point of the widget at which the widget will be positioned with the relative value. The following +picture should make this clear. In the picture `leftRelAnchor(0.5f, 0.3f)` is called. + +![anchor.png](anchor.png) + +Here the anchor is placed at `0.3f`, which is about a third of the widget. +And that anchor is positioned at `0.5f` of the parent widget (the center). +Try imagining what happens with different anchor values and play around with it by yourself. + +If we had called `leftRel(float val, int offset, float anchor)`, then the offset would be added after the anchor +and relative position calculation. + +## Combining Size and Position + +Of course, you can call multiple position and size methods, but you should be aware of its effects and limitations. + +Each axis (x and y) has 3 setters (x has `left()`, `right()` and `width()`, y has `top()`, `bottom()` and `height()`) +without including all the variations. + +!!! Note + You can call at most 2 setters for each axis, since with two properties set the last one can always be calculated! + +For example of you call `left()` and `right()` then the width can be calculated with `right - left`. +Setting all three properties for an axis will cause a crash (?). + +!!! Note + You don't need to call any setters. The position defaults to (0|0) and the size defaults to 18 by 18 (for most widgets). + +## Changing the relative Parent +By default, the size and position are calculated relative to the direct widgets parent. But that can be changed with +`relative(Area)`, `relative(IGuiElement)` and `relativeToScreen()`. +The parent of all panels is by default the screen. + +!!! Warning + Changing the relative widget might cause some unexpected results in some edge cases. Please notify me if you run + into one of those. diff --git a/docs/mod-wiki/modularui/synced_gui_tutorial.md b/docs/mod-wiki/modularui/synced_gui_tutorial.md index d31881f..877f357 100644 --- a/docs/mod-wiki/modularui/synced_gui_tutorial.md +++ b/docs/mod-wiki/modularui/synced_gui_tutorial.md @@ -6,8 +6,9 @@ In this tutorial we will open a GUI on right clicking a block. ## Creating the Block At the top we subscribe to some events to register the block and the item form. Whats interesting for us is the method at the bottom `onBlockActivated()`. This is called when the block is right clicked. -Inside we first check if the method is called on server side. This is important. **Synced GUI's MUST be opened ONLY from server side!**. -Then we simply call `GuiInfos.TILE_ENTITY.open(playerIn, worldIn, pos);`. This will find the tile entity at the blocks position and tries to open the GUI on client and server side. +Inside we first check if the method is called on server side. This is important. **Synced GUI's MUST be opened ONLY from +server side!**. Then we simply call `GuiInfos.TILE_ENTITY.open(playerIn, worldIn, pos);`. This will find the tile entity +at the blocks position and tries to open the GUI on client and server side. ```java public class TutorialBlock extends Block implements ITileEntityProvider { @@ -18,7 +19,7 @@ public class TutorialBlock extends Block implements ITileEntityProvider { ResourceLocation rl = new ResourceLocation("tutorial_mod", "test_block"); testBlock.setRegistryName(rl); testItemBlock.setRegistryName(rl); - GameRegistry.registerTileEntity(TestTile.class, rl); + GameRegistry.registerTileEntity(TutorialTile.class, rl); } @SubscribeEvent @@ -40,7 +41,7 @@ public class TutorialBlock extends Block implements ITileEntityProvider { @Nullable @Override public TileEntity createNewTileEntity(@NotNull World worldIn, int meta) { - return new TestTile(); + return new TutorialTile(); } @Override @@ -54,9 +55,11 @@ public class TutorialBlock extends Block implements ITileEntityProvider { ``` ## Creating the TileEntity -This is fairly simple. Extend `TileEntity` and implement `IGuiHolder`. Then override `buildUI()`. You can also override `createScreen()` to create a custom screen, but most of the time you wont need that. +This is fairly simple. Extend `TileEntity` and implement `IGuiHolder`. Then override `buildUI()`. You can also override +`createScreen()` to create a custom screen, but most of the time you won't need that. -Inside the `buildUI()` is where the fun stuff happens. The method is called on both client and server side, but only on client side the widgets are kept. But on both sides the syncing information is kept. +Inside the `buildUI()` is where the fun stuff happens. The method is called on both client and server side, but only on +client side the widgets are kept. But on both sides the syncing information is kept. Here we currently only create a panel and attach the player inventory. **The GUI must be synced for ANY slots to work!** ```java public class TutorialTile extends TileEntity implements IGuiHolder { @@ -73,7 +76,9 @@ Our GUI now looks like this. We have a correctly positioned player inventory at ![grafik](https://github.com/CleanroomMC/ModularUI/assets/45517902/affc34c2-e89a-4f5a-9010-8ac352145cc9) ## Syncing custom values -Now let's add a progress bar to the GUI. For that we first make the tile ticking. Inside `update()` we upadte the progress variable, but only on server side to simulate a working machine (and to showcase syncing). Once the progress reaches 100 ticks it's reset to 0. 100 ticks equals 5 seconds. +Now let's add a progress bar to the GUI. For that we first make the tile ticking by implementing `ITickable` into the +`TutorialTile`. Inside `update()` we upadte the progress variable, but only on server side to simulate a working machine +(and to showcase syncing). Once the progress reaches 100 ticks it's reset to 0. 100 ticks equals 5 seconds. ```java private int progress = 0; @@ -102,8 +107,12 @@ The whole syncing information is in this line: ```java .value(new DoubleSyncValue(() -> this.progress / 100.0, val -> this.progress = (int) (val * 100)))); ``` -`value()` accepts an instance of `IDoubleValue`. If we want the value to be synced we need to use `DoubleSyncValue`. The constructor needs to arguments. A getter as `DoubleSupplier` and a setter as `DoubleConsumer`. The progress widget wants a double value between 0 and 1 so we need to divide by the maximum value (100). The getter is called on server side on compared by a cached value to figure out if it needs to be synced. -On client side the setter is called to update our progress field on client side. But since only the widget needs that value and nothing else we could also pass in `null` for the second argument (the DoubleSyncValue caches it's own progress value based on the passed getter). +`value()` accepts an instance of `IDoubleValue`. If we want the value to be synced we need to use `DoubleSyncValue`. The +constructor needs to arguments. A getter as `DoubleSupplier` and a setter as `DoubleConsumer`. The progress widget wants +a double value between 0 and 1 so we need to divide by the maximum value (100). The getter is called on server side on +compared by a cached value to figure out if it needs to be synced. On client side the setter is called to update our +progress field on client side. But since only the widget needs that value and nothing else we could also pass in `null` +for the second argument (the DoubleSyncValue caches it's own progress value based on the passed getter). You can disable JEI in your synced GUI by adding this line into your `buildUI()` method ```java diff --git a/mkdocs.yml b/mkdocs.yml index cb7b7d6..0c57287 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -32,6 +32,8 @@ nav: - Getting Started: mod-wiki/modularui/getting_started.md - Client GUI tutorial: mod-wiki/modularui/client_gui_tutorial.md - Synced GUI tutorial: mod-wiki/modularui/synced_gui_tutorial.md + - Sizing and Positioning: mod-wiki/modularui/sizing_and_positioning.md + - Framework: mod-wiki/modularui/framework.md - Proposal: - Standard: - Minecraft Technical Metric System: proposal/standard/mtms.md From 27903a8217d0b45372acbf035c8d78b668cdefb9 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Tue, 17 Oct 2023 11:15:45 +0200 Subject: [PATCH 5/7] start theme docs --- docs/mod-wiki/modularui/themes.md | 136 ++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 137 insertions(+) create mode 100644 docs/mod-wiki/modularui/themes.md diff --git a/docs/mod-wiki/modularui/themes.md b/docs/mod-wiki/modularui/themes.md new file mode 100644 index 0000000..468fc82 --- /dev/null +++ b/docs/mod-wiki/modularui/themes.md @@ -0,0 +1,136 @@ + +!!! Note + Themes can only be registered for GUIs made with ModularUI. + +## Reloading themes + +You can reload themes by either reloading resources (which is slow) or by running the `/reloadThemes` command. + +## For mod developers + +### Registering themes + +First create a `JsonBuilder` instance (`com.cleanroommc.modularui.utils.JsonBuilder`). This will be your theme data. +ModularUI will automatically parse the json. +Next you need to register it. Make sure to do that before resource packs are loaded (that's when themes gets loaded and +parsed). `FMLPreInit` works fine. + +```java +JsonBuilder myTheme = new JsonBuilder(); +IThemeApi.get().registerTheme("mymodid:my_theme", myTheme); +``` + +It is not required to have the mod id in the name, but it will help identifying the theme. +Multiple themes with the same name can be registered. Themes that are added later will override all properties of all +previously registered themes. + +You can edit the theme before and after you registered it. Just make sure it's before the themes are loaded. +If you are unsure you can use the `ReloadThemeEvent.Pre`. + +### Applying a theme to a GUI + +There are two ways to set a theme in a GUI. + +1. `IThemeApi.get().registerThemeForScreen(String screenOwner, String mainPanelName, String themeName)` + This method can be used at any point. Registering another theme with the same screen name will overwrite the old one. +2. When you create the screen: `new ModularScreen(...).useTheme(String themeName)` + +If both methods are used, the first will always take priority. + +## For resource packs + +First create new file in your resource pack at `assets/modularui/themes.json`. You can replace `modularui` with any +loaded mod id here. +In this file you will define themes and where they are located as well as setting themes for GUIs. + +Let's look at the `themes.json` file that is shipped with ModularUI. + +```json +{ + "vanilla": "modularui:vanilla", + "vanilla_dark": "modularui:vanilla_dark", + "screens": { + "modularui:test": "vanilla_dark" + } +} +``` + +### Registering themes + +The first line is `"vanilla": "modularui:vanilla"`. `vanilla` is the name of the theme and `modularui:vanilla` is the +path to the theme file. +This means the theme file for `vanilla` should be at `assets/modularui/themes/vanilla.json`. +The next line defines a new theme with the name `vanilla_dark` with the theme file located at +`assets/modularui/themes/vanilla_dark.json`. + +### Applying a theme to a GUI + +Let's look at the next line: `"screens": {}` + +Inside the curly brackets we can set themes for screens. The format is `"screen_owner:main_panel_name": "theme_name"`. +So in the example above `modularui:test` the full screen name and `vanilla_dark` is the theme name (which we defined +before). + +## Creating themes + +Here we will take a look what the theme file can look like. If you are a mod developer you can directly translate to +your `JsonBuilder`. + +Let's look at an example. This is what the default vanilla theme as a json file would look like. + +```json +{ + "parent": "DEFAULT", + "background": null, + "hoverBackground": null, + "color": "#FFFFFFFF", + "textColor": "#FF404040", + "textShadow": false, + "panel": { + "background": { + "type": "texture", + "id": "vanilla_background" + } + }, + "button": { + "background": { + "type": "texture", + "id": "vanilla_button" + }, + "textColor": "#FFFFFFFF", + "textShadow": true + }, + "itemSlot": { + "background": { + "type": "texture", + "id": "slot_item" + }, + "slotHoverColor": "#60FFFFFF" + }, + "fluidSlot": { + "background": { + "type": "texture", + "id": "slot_fluid" + }, + "slotHoverColor": "#60FFFFFF" + }, + "textField": { + "textColor": "#FFFFFFFF", + "markedColor": "#FF2F72A8" + }, + "toggleButton": { + "background": { + "type": "texture", + "id": "vanilla_button" + }, + "textColor": "#FFFFFFFF", + "textShadow": true, + "selectedBackground": { + "type": "texture", + "id": "slot_item" + }, + "selectedHoverBackground": null, + "selectedColor": "0xFFBBBBBB" + } +} +``` diff --git a/mkdocs.yml b/mkdocs.yml index 0c57287..487438d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,6 +34,7 @@ nav: - Synced GUI tutorial: mod-wiki/modularui/synced_gui_tutorial.md - Sizing and Positioning: mod-wiki/modularui/sizing_and_positioning.md - Framework: mod-wiki/modularui/framework.md + - Themes: mod-wiki/modularui/themes.md - Proposal: - Standard: - Minecraft Technical Metric System: proposal/standard/mtms.md From 0398f70866efa1039ce98c8e8c5611f8e8de4a24 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Wed, 18 Oct 2023 21:10:34 +0200 Subject: [PATCH 6/7] docs for json drawables, color and alignment --- docs/mod-wiki/modularui/json/alignment.md | 34 ++++ docs/mod-wiki/modularui/json/color.md | 100 ++++++++++++ docs/mod-wiki/modularui/json/drawable.md | 184 ++++++++++++++++++++++ docs/mod-wiki/modularui/json/theme.md | 64 ++++++++ docs/mod-wiki/modularui/themes.md | 66 +------- mkdocs.yml | 5 + 6 files changed, 390 insertions(+), 63 deletions(-) create mode 100644 docs/mod-wiki/modularui/json/alignment.md create mode 100644 docs/mod-wiki/modularui/json/color.md create mode 100644 docs/mod-wiki/modularui/json/drawable.md create mode 100644 docs/mod-wiki/modularui/json/theme.md diff --git a/docs/mod-wiki/modularui/json/alignment.md b/docs/mod-wiki/modularui/json/alignment.md new file mode 100644 index 0000000..3548c48 --- /dev/null +++ b/docs/mod-wiki/modularui/json/alignment.md @@ -0,0 +1,34 @@ +Alignment is an object with an x and y component. Where 0.0 means start and 1.0 means end. + +## Alignment by name + +ModularUI has 9 default alignments. + +- `top_left` or `tl` +- `top_center` or `tc` +- `top_right` or `tr` +- `center_left` or `cl` +- `center` or `c` +- `center_right` or `cr` +- `bottom_left` or `bl` +- `bottom_center` or `bc` +- `bottom_right` or `br` + +!!! Example +```json +{ + "alignment": "top_center" +} +``` + +You can also create a new alignment. + +!!! Example +```json +{ + "alignment": { + "x": 0.3, + "y": 0.6666666 + } +} +``` diff --git a/docs/mod-wiki/modularui/json/color.md b/docs/mod-wiki/modularui/json/color.md new file mode 100644 index 0000000..ea3b6c5 --- /dev/null +++ b/docs/mod-wiki/modularui/json/color.md @@ -0,0 +1,100 @@ +There are many different way to define color in JSON + +## Hexadecimal number + +The simplest way is by using hexadecimal numbers. You can do that be prefixing your number string with `0x`, `0X` or `#`. +The format is `AARRGGBB`. If `A` (alpha) is not set, it defaults to full opacity + +!!! Example + ```json + { + "color": "#FFFFFF" + } + ``` + + +The following formats can all have the `alpha` or `a` property, with a value from either 0.0 to 1.0 or from 0 to 255. +If you want to use the 0.0 to 1.0 range you need use a `.`. `1` will use the +0 to 255 range and is very low. `1.0` will use the 0.0 to 1.0 range and is full opacity. + +## RGB + +- `red` or `r`: The red value from 0 to 255 +- `green` or `g`: The green value from 0 to 255 +- `blue` or `b`: The blue value from 0 to 255 + +!!! Example + ```json + { + "color": { + "r": 200, + "g": 0, + "b": 44, + "alpha": 1.0 + } + } + ``` + +Here you can see how alpha can be added. + +## HSV + +- `hue` or `h`: The hue value from 0 to 360 (wraps around) (default is 0) +- `saturation` or `s`: The saturation from 0.0 to 1.0 (default is 0.0) +- `value` or `v`: The value from 0.0 to 1.0 (default is 1.0) + +If `value` is not defined, [HSL](#hsl) will be used. + +!!! Example + ```json + { + "color": { + "hue": 120, + "saturation": 0.5, + "value": 0.75 + } + } + ``` + +## HSL + +- `hue` or `h`: The hue value from 0 to 360 (wraps around) (default is 0) +- `saturation` or `s`: The saturation from 0.0 to 1.0 (default is 0.0) +- `lightness` or `l`: The value from 0.0 to 1.0 (default is 0.5) + +!!! Example + ```json + { + "color": { + "hue": 120, + "saturation": 0.5, + "lightness": 0.75 + } + } + ``` + +!!! Note + The saturation is not the same from [HSV](#hsv) as from [HSL](#hsl) (they are calculated slightly different), + but the hue is. + +## CMYK + +- `cyan` or `c`: The cyan value from 0.0 to 1.0 (default is 1.0) +- `magenta` or `m`: The cyan value from 0.0 to 1.0 (default is 1.0) +- `yellow` or `y`: The cyan value from 0.0 to 1.0 (default is 1.0) +- `black` or `k`: The cyan value from 0.0 to 1.0 (default is 1.0) + +!!! Example + ```json + { + "color": { + "c": 1.0, + "m": 0.5, + "y": 0.75, + "k": 0.2 + } + } + ``` + +!!! Warning + You can NOT mix any of those formats! (except of course alpha) diff --git a/docs/mod-wiki/modularui/json/drawable.md b/docs/mod-wiki/modularui/json/drawable.md new file mode 100644 index 0000000..8627310 --- /dev/null +++ b/docs/mod-wiki/modularui/json/drawable.md @@ -0,0 +1,184 @@ +This page is about defining drawables in json files. These are used in backgrounds on themes for example. + +In all examples we will use `background`. + +Drawables have a type (for example images). Each type has different properties. +For each type each property will be listed and explained. + +## Empty Drawable + +Type name: `empty` or `null` + +Empty Drawables are special since they don't need to be an object. The can juts be `null`. + +Empty Drawables don't have any properties. + +Example: + +Both definitions are equivalent. + +```json +{ + "background1": null, + "background2": { + "type": "empty" + } +} +``` + +## Images + +Type name: `texture` + +You can get an existing image with `name` or `id`. In this case all other properties will be ignored. + +```json +{ + "background": { + "type": "texture", + "id": "vanilla_background" + } +} +``` + +Or you can define a new image. An image has multiple subtypes. + +1. Full image: Uses the whole image at the given path (will be stretched to fit the render size) +2. Sub image: Uses a rectangular part of an image (will be stretched to fit the render size) +3. Adaptable image: has a border and a plain center. The border is drawn separately, so it won't be stretched no matter + how large the texture is drawn. The center should be plain because it will be stretched to fit the render size. +4. Tiled image: The image will be drawn multiples times at its original size like tiles to fit the render size. This can + be combined with adaptable image. + +For all image types you need the `location` property. It defines where the image file is. The value is a resource +location. +Check out +the [GroovyScript docs](https://groovyscript-docs.readthedocs.io/en/latest/groovyscript/rl/#converting-to-file-path) to +find out more. + +### Full image + +Full images only need the `location property`, which is explained above. + +### Sub image + +Here you want to define a rectangle inside the image. You can do that using `x`, `y`, `w`, `h`, `iw` and `ih`. All these +properties are in pixel. `w` is also `width`, `h` is also `height`, `iw` is also `imageWidth` and `ih` is +also `imageHeight`. + +Or you can define a rectangle with `u0`, `v0`, `u1` and `v1`. These are relative values from 0.0 to 1.0. `u` is the +x-axis and `v` the y-axis. 0 means start and 1 means end. + +!!! Warning +You can NOT mix both types! + +### Adaptable image + +Can be a full image or a sub image. To make an image adaptable you need `borderX` and/or `borderY` or just `border` ( +sets both axis). +`borderX` is the border size on the x-axis. All properties are in pixels. + +### Tiled image + +Can be a full image or a sub image. Can also have border properties for adaptable image. +For tiled images you need `"tiled": true` and `imageWidth` (or `iw`) and `imageHeigth` (or `ih`). + +### Example + +This is an example for an adaptable sub image (we set the values to still be the full image). + +```json +{ + "background": { + "type": "texture", + "location": "modularui:gui/background/background", + "imageWidth": 195, + "imageHeight": 136, + "x": 0, + "y": 0, + "width": 195, + "height": 136, + "border": 4 + } +} +``` + +## Colored rectangle + +Type name: `color` or `rectangle` + +Properties: + +- `cornerRadius` is the corner radius. Default is 0 +- `cornerSegments` is the amount of segments the corner has if the corner radius is not 0. Default is 6. Lower means + more pointy but faster drawing, higher means smoother but slower drawing. +- `color` is the color of the whole rectangle (see [colors](color.md)) + +We can also set colors for each corner individually. This way we can create beautiful gradients. + +- `colorTop` sets the color of the top left and top right corner. `colorBottom`, `colorLeft` and `colorRight` work + analogue +- `colorTopLeft` or `colorTL` sets the color of the top left corner. `colorTopRight`, `colorBottomLeft` + and `colorBottomRight` work analogue + +Of course, you can combine multiple colors. For example, you can set `color` and then `colorBL`. This will make all +corners +have the color of `color` except the bottom left corner which will have the `colorBL` color. + +## Ellipse / Circle + +Type name: `ellipse` + +The ellipse will always stretch to its render size. It will only be a circle if render width and render height are the +same. + +Properties: + +- `color` sets the color of the whole circle +- `colorInner` sets the center color, creating a gradient +- `colorOuter` sets the outer color, creating a gradient +- `segments` is the amount of edges the circle will have. Default is 40. Lower means more pointer and, but faster + drawing and higher means smoother and slower drawing. With low segment count you can also draw polygons + +## Text + +Type name: `text` + +Properties: + +- `text`, `string` or `key`: The text (Required) +- `lang` or `translate`: If the text is a lang key and should be translated (Default is false) +- `color`: Text color (see [color](color.md)) (Uses color of the widget theme if applicable by default) +- `shadow`: True if the text should have a shadow. (Uses shadow of the widget theme if applicable by default) +- `align` or `alignment`: The alignment of the text in the render size. (see [alignment](alignment.md)) (Default is center) +- `scale`: The scale to draw text at. (Default is 1.0) + +!!! Example + ```json + { + "type": "text", + "text": "Hello World", + "lang": false + } + ``` + +The text can also be an array. In this case the `lang` property is ignored. +Each of the elements in the array can either be a string or an object with the `text` and `lang` property. Those objects +can also have any style property like `color` and `shadow`. + +!!! Example + ```json + { + "type": "text", + "text": [ + "Hello ", + { + "text": "this.part.is.translated", + "lang": true + }, + "I18n:this.part.is.also.translated" + ] + } + ``` + +As you can see in the example above you can also start a string with `I18n:` to make it translated. diff --git a/docs/mod-wiki/modularui/json/theme.md b/docs/mod-wiki/modularui/json/theme.md new file mode 100644 index 0000000..ddd8962 --- /dev/null +++ b/docs/mod-wiki/modularui/json/theme.md @@ -0,0 +1,64 @@ + +Make sure to check out [how to register themes](../themes.md). + +Here we will take a look what the theme file can look like. If you are a mod developer you can directly translate to +your `JsonBuilder`. + +Let's look at an example. This is what the default vanilla theme as a json file would look like. + +```json +{ + "parent": "DEFAULT", + "background": null, + "hoverBackground": null, + "color": "#FFFFFFFF", + "textColor": "#FF404040", + "textShadow": false, + "panel": { + "background": { + "type": "texture", + "id": "vanilla_background" + } + }, + "button": { + "background": { + "type": "texture", + "id": "vanilla_button" + }, + "textColor": "#FFFFFFFF", + "textShadow": true + }, + "itemSlot": { + "background": { + "type": "texture", + "id": "slot_item" + }, + "slotHoverColor": "#60FFFFFF" + }, + "fluidSlot": { + "background": { + "type": "texture", + "id": "slot_fluid" + }, + "slotHoverColor": "#60FFFFFF" + }, + "textField": { + "textColor": "#FFFFFFFF", + "markedColor": "#FF2F72A8" + }, + "toggleButton": { + "background": { + "type": "texture", + "id": "vanilla_button" + }, + "textColor": "#FFFFFFFF", + "textShadow": true, + "selectedBackground": { + "type": "texture", + "id": "slot_item" + }, + "selectedHoverBackground": null, + "selectedColor": "0xFFBBBBBB" + } +} +``` diff --git a/docs/mod-wiki/modularui/themes.md b/docs/mod-wiki/modularui/themes.md index 468fc82..b559578 100644 --- a/docs/mod-wiki/modularui/themes.md +++ b/docs/mod-wiki/modularui/themes.md @@ -37,6 +37,8 @@ There are two ways to set a theme in a GUI. If both methods are used, the first will always take priority. +Checkout [this page](json/theme.md) to find out what properties you can add to the builder. + ## For resource packs First create new file in your resource pack at `assets/modularui/themes.json`. You can replace `modularui` with any @@ -71,66 +73,4 @@ Inside the curly brackets we can set themes for screens. The format is `"screen_ So in the example above `modularui:test` the full screen name and `vanilla_dark` is the theme name (which we defined before). -## Creating themes - -Here we will take a look what the theme file can look like. If you are a mod developer you can directly translate to -your `JsonBuilder`. - -Let's look at an example. This is what the default vanilla theme as a json file would look like. - -```json -{ - "parent": "DEFAULT", - "background": null, - "hoverBackground": null, - "color": "#FFFFFFFF", - "textColor": "#FF404040", - "textShadow": false, - "panel": { - "background": { - "type": "texture", - "id": "vanilla_background" - } - }, - "button": { - "background": { - "type": "texture", - "id": "vanilla_button" - }, - "textColor": "#FFFFFFFF", - "textShadow": true - }, - "itemSlot": { - "background": { - "type": "texture", - "id": "slot_item" - }, - "slotHoverColor": "#60FFFFFF" - }, - "fluidSlot": { - "background": { - "type": "texture", - "id": "slot_fluid" - }, - "slotHoverColor": "#60FFFFFF" - }, - "textField": { - "textColor": "#FFFFFFFF", - "markedColor": "#FF2F72A8" - }, - "toggleButton": { - "background": { - "type": "texture", - "id": "vanilla_button" - }, - "textColor": "#FFFFFFFF", - "textShadow": true, - "selectedBackground": { - "type": "texture", - "id": "slot_item" - }, - "selectedHoverBackground": null, - "selectedColor": "0xFFBBBBBB" - } -} -``` +Checkout [this page](json/theme.md) to find out how to write themes. diff --git a/mkdocs.yml b/mkdocs.yml index 487438d..e287edd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,11 @@ nav: - Sizing and Positioning: mod-wiki/modularui/sizing_and_positioning.md - Framework: mod-wiki/modularui/framework.md - Themes: mod-wiki/modularui/themes.md + - Json: + - Drawables: mod-wiki/modularui/json/drawable.md + - Color: mod-wiki/modularui/json/color.md + - Alignment: mod-wiki/modularui/json/alignment.md + - Theme: mod-wiki/modularui/json/theme.md - Proposal: - Standard: - Minecraft Technical Metric System: proposal/standard/mtms.md From f0a7f1019cc10517df2b5a78fd00596e66e0a3ea Mon Sep 17 00:00:00 2001 From: brachy84 Date: Thu, 19 Oct 2023 14:48:46 +0200 Subject: [PATCH 7/7] complete theme docs --- docs/mod-wiki/modularui/framework.md | 10 +++ docs/mod-wiki/modularui/json/color.md | 2 +- docs/mod-wiki/modularui/json/drawable.md | 80 ++++++++++++++++++++++++ docs/mod-wiki/modularui/json/theme.md | 34 +++++++++- 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/docs/mod-wiki/modularui/framework.md b/docs/mod-wiki/modularui/framework.md index c8147c7..0a5df60 100644 --- a/docs/mod-wiki/modularui/framework.md +++ b/docs/mod-wiki/modularui/framework.md @@ -56,7 +56,17 @@ This class has a lot of useful methods, too many to list them all. But you can t to structure it and make it clean. ## WindowManager + Keeps track of all panels and the main panels. Handles opening and closing panels ## GuiSyncManager + Manages sync values. This is the only class (with `ModularContainer`) that exists on client and server side. + +## GuiScreenWrapper + +This is the minecraft `GuiContainer` class which wraps the `ModularScreen`. This is an internal class. + +## ModularContainer + +This is the minecraft `Container` class. This is an internal class. diff --git a/docs/mod-wiki/modularui/json/color.md b/docs/mod-wiki/modularui/json/color.md index ea3b6c5..8c78a37 100644 --- a/docs/mod-wiki/modularui/json/color.md +++ b/docs/mod-wiki/modularui/json/color.md @@ -8,7 +8,7 @@ The format is `AARRGGBB`. If `A` (alpha) is not set, it defaults to full opacity !!! Example ```json { - "color": "#FFFFFF" + "color": "#FFFFFF" } ``` diff --git a/docs/mod-wiki/modularui/json/drawable.md b/docs/mod-wiki/modularui/json/drawable.md index 8627310..85dffff 100644 --- a/docs/mod-wiki/modularui/json/drawable.md +++ b/docs/mod-wiki/modularui/json/drawable.md @@ -182,3 +182,83 @@ can also have any style property like `color` and `shadow`. ``` As you can see in the example above you can also start a string with `I18n:` to make it translated. + +## Item + +Type name: `item` + +- `item`: The format is `mod:item_id:meta` where meta is optional +- `nbt`: nbt data (untested) + +!!! Example + ```json + { + "background": { + "type": "item", + "item": "minecraft:diamond" + } + } + ``` + +## Icon + +An icon is a drawable wrapper which can draw a drawable at a fixed size. + +Type name: `icon` + +Properties: + +- `drawable` or `icon`: The wrapped drawable. (Required) +- `width` or `w`: The width to render the drawable at. +- `height` or `h`: The height to render the drawable at. +- `autoWidth` and `autoHeight`: True if the width/height should match the render size (how normal drawables work). +- `autoSize`: True if the width and height should match the render size (how normal drawables work). (Default is true) +- `alignment` or `align`: The alignment of the drawable in the render size. (see [alignment](alignment.md)) (default is center) + +You can also set margins. But they only work if the width (for left and right) or the height (for top and bottom) is set to auto. +Multiple margins can be combined. + +- `margin`: The margin on all edges +- `marginHorizontal` and `marginVertical`: The margin on horizontal (left and right) or vertical (top and bottom) edges +- `marginTop`, `marginBottom`, `marginLeft`, `marginRight`; The margin of each edge + +!!! Example + ```json + { + "background": { + "type": "icon", + "drawable": { + "type": "...", + "...": "..." + }, + "width": 18, + "height": 18 + } + } + ``` + +## Drawable array + +A drawable can also be multiple drawable. You can do that by using square brackets `[]` instead of curly brackets `{}`. +And inside there you just define multiple drawable objects + +!!! Example + ```json + { + "background": [ + { + "type": "...", + "...": "..." + }, + { + "type": "...", + "...": "..." + }, + { + "type": "...", + "...": "..." + } + + ] + } + ``` diff --git a/docs/mod-wiki/modularui/json/theme.md b/docs/mod-wiki/modularui/json/theme.md index ddd8962..fecd602 100644 --- a/docs/mod-wiki/modularui/json/theme.md +++ b/docs/mod-wiki/modularui/json/theme.md @@ -1,7 +1,7 @@ Make sure to check out [how to register themes](../themes.md). -Here we will take a look what the theme file can look like. If you are a mod developer you can directly translate to +Here we will take a look what the theme file can look like. If you are a mod developer you can directly translate it to your `JsonBuilder`. Let's look at an example. This is what the default vanilla theme as a json file would look like. @@ -62,3 +62,35 @@ Let's look at an example. This is what the default vanilla theme as a json file } } ``` + +First we have the `parent` property. This defines the parent theme. If a theme does not define a widget theme, it will +be taken from its parent. If the `parent` property is not set, it defaults to `DEFAULT`, which is just the vanilla theme. + +After that we have the `color`, `background`, `hoverBackground`, `textColor` and `textShadow` properties. These are +fallback properties of [widget themes](#widget-themes). You can put any properties that any widget theme can have here. +If a widget theme does not have said property it will fall back to the top level property if defined. + +For `color` and `textColor` see [color](color.md). For `background` and `hoverBackground` see [drawables](drawable.md). + +Next we have objects defined with the property name `panel`, `button`, `itemSlot`, `fluidSlot`, `textField` and `toggleButton`. +These are widget themes. These are all widget themes ModularUI provides. Addons may add more. + +## Widget themes + +Widgets which don't use one of the existing widget themes use the fallback properties. + +All widget themes have the properties `color`, `background`, `hoverBackground`, `textColor` and `textShadow`. Which are +all mostly self-explanatory. `color` is applied additionally to the background (if possible). + +The `itemSlot` and `fluidSlot` also have the `slotHoverColor`, which is just the rendered color when the slot is hovered. +Don't use full opacity here. Otherwise, you won't be able to see the item. + +The `textField` theme has the `markedColor` property which is the marked text background. + +The `toggleButton` has `selectedBackground`, `selectedHoverBackground` and `selectedColor` which are all self-explanatory. + +!!! Note + All widget themes are optional. You can define as many as you like. Not defined widget themes will be taken from the + parent theme + + All properties of widget themes (and the fallback properties) are optional. \ No newline at end of file