# Home

{% hint style="danger" %}
This is an archive of the old GitHub wiki! This will be re-written in the near future.
{% endhint %}

Welcome to YACL's wiki! This page will guide you on how to use YACL:

### Notes

A few things to clear up before we get started...

* This page will be laid out in the chronological order a developer would use to implement YACL.
* This mod is only available for Fabric and Quilt.
* All code examples presume you use Yarn mappings.
* You must have basic/intermediate Java knowledge.

### A quick overview

For people who just want to skip to the full example, [click here](#all-together)

### Backbones of the config

The main class that contains everything is `YetAnotherConfigLib` (how fitting!). This interface accepts a name, config categories, a save function, and an init function.

YACL's API is builder based, not class based, so everything is defined inside of a method, let's pretend we have a config class, it has a save function, and a few properties, and a method called `MyConfig#createGui()`

```java
import net.minecraft.client.screen.Screen;

public class MyConfig {
    public boolean booleanToggle = true;
    public int intSlider = 5;

    public void save() { /* save your config! */ }

    public Screen createGui(Screen parent) {
        // time to use YOCL!
    }
}
```

But let's forget about the rest of this class for now and start constructing YetAnotherConfigLib...

```java
YetAnotherConfigLib.createBuilder()
        .name(Text.of("Mod Name"))
        .save(MyConfig::save)
        .build()
```

Here you can see the general syntax for the API beginning to shape, however, this isn't very useful, let's add a category...

```java
YetAnotherConfigLib.createBuilder()
        .title(Text.of("Mod Name"))
        .category(ConfigCategory.createBuilder()
                .name(Text.of("My Category")
                .tooltip(Text.of("This displays when you hover over a category button")) // optional
                .build())
        .save(MyConfig::save)
        .build()
```

Still, not very useful, but here is where it gets good! Let's forget about what we have so far and just focus on `Option`

### Options

Options are broken down into two main parts, a binding and a controller.

#### Bindings

Bindings are simple, you *bind* a property to an interface. This provides essential functionality to query and set values in your config, there are two types of bindings you can use by default, a generic binding and a minecraft binding.

**Generic**

This is the Binding you will be using most often, it accepts a default value, a getter, and a setter, like this...

```java
Binding.generic(0 /* default value for setting */, () -> this.booleanToggle, newValue -> this.booleanToggle = newValue)
```

**Minecraft**

You can also bind an option found in the `GameOptions` class like this...

```java
Binding.minecraft(Minecraft.getInstance().gameOptions.getAutoJump())
```

**Immutable**

There is also an option to make a binding immutable (cannot be changed). This may be useful for labels

```java
Binding.immutable(value)
```

#### Controllers

Controllers provide YACL a graphical widget to display and for users to interact with, this functionality has been completely separated from the Option itself so you can define multiple ways of displaying the same datatype.

By default there are only a handful of controllers available, but it is super easy to add another controller (later in the wiki) and covers the basics, booleans, numbers and enums.

**BooleanController**

A simple controller that displays `Text` based on the state of the boolean. There are a few pre-defined value formatters: `ON_OFF` (default), `TRUE_FALSE` and `YES_NO`. These can be found in the class.

```java
new BooleanController(option /* provided by builder */, BooleanController.YES_NO_FORMATTER /* default ON_OFF, optional */)
```

**TickBoxController**

A controller that displays a tickbox, indicating true or false.

```java
new TickBoxController(option /* provided by builder */)
```

**EnumController**

A simple controller that displays `Text` based on the name of the enum constant (this can be customised). By default, this controller first looks to see if the enum implements `NameableEnum`, which provides a `Text`, falling back on `Enum#toString()`

```java
new EnumController(option /* provided by builder */, enumConstant -> Text.of(enumConstant.toString()) /* optional */)
```

**CyclingListController**

Any `Iterable` can be passed to this controller. It behaves just like `EnumController` and can be cycled with a click.

```java
new CyclingListController(option /* provided by builder */, List.of("A", "B", "C"), entry -> entry.toLowerCase() /* optional */)
```

**SliderController**

There is a slider controller for every common number datatype:

* `IntegerSliderController`
* `FloatSliderController`
* `DoubleSliderController`
* `LongSliderController`

These sliders accept a minimum value, a maximum value and an interval (slider increment) and optionally a value formatter. By default, doubles format to two decimal places, floats one, and all four are separated with commas every three digits. (again, can be customized)

In this example, I chose to use an integer but all are the same.

```java
new IntegerSliderController(option /* provided by builder */, 0 /* min */, 10 /* max */, 1 /* interval */)
```

**ActionController**

Simply displays some text on the right and executes the ButtonOption action on press. By default, the text reads `EXECUTE` but this can be customized.

```java
new ActionController(option /* provided by builder */, Text.of("Run") /* optional */)
```

**StringController**

A custom text field implementation.

```java
new StringController(option /* provided by builder */)
```

**ColorController**

A hex color field with a color preview.

```java
new ColorController(option /* provided by builder */, allowAlpha /* default false */)
```

**LabelController**

Renders some `Text`, should be used with an immutable binding. Allows user to click on styled text or hover like in the chat.

```java
new LabelController(option /* provided by builder */)
```

#### Building an option

Here you can see a basic example of an option. Please note that there is a shorthand function for `Binding.generic` being used (see here)

```java
Option.createBuilder(boolean.class)
        .name(Text.of("My Boolean Option"))
        .tooltip(Text.of("This option displays the basic capabilities of YetAnotherConfigLib")) // optional
        .binding(
                true, // default
                () -> this.booleanToggle, // getter
                newValue -> this.booleanToggle = newValue // setter
         )
        .controller(BooleanController::new)
        .build()
```

### All together!

That's all you need to know to build YetAnotherConfigLib, let's put everything together!

```java
import net.minecraft.client.screen.Screen;

public class MyConfig {
    public boolean booleanToggle = true;
    public int intSlider = 5;

    public void save() { /* save your config! */ }

    public Screen createGui(Screen parent) {
        YetAnotherConfigLib.createBuilder()
                .title(Text.of("Mod Name"))
                .category(ConfigCategory.createBuilder()
                        .name(Text.of("My Category"))
                        .tooltip(Text.of("This displays when you hover over a category button")) // optional
                        .option(Option.createBuilder(boolean.class)
                                .name(Text.of("My Boolean Option"))
                                .tooltip(Text.of("This option displays the basic capabilities of YetAnotherConfigLib")) // optional
                                .binding(
                                        true, // default
                                        () -> this.booleanToggle, // getter
                                        newValue -> this.booleanToggle = newValue // setter
                                 )
                                .controller(BooleanController::new)
                                .build())
                        .build())
                .save(MyConfig::save)
                .build()
                .generateScreen(parent);
    }
}
```

Make sure you notice the last line where a `Screen` is generated.

![basic example](https://user-images.githubusercontent.com/43245524/188279998-f099337e-d5ca-4142-ad29-7876b79d1d25.png)

### Advanced features

#### Option Groups

Instead of just adding an option to a category, you can also add groups to a category. Groups act much like subcategories, they are displayed as a separator in the option list. They also don't need to be named and just be used as a spacer. You can also set them to be collapsed by default if there are too many.

```java
ConfigCategory.createBuilder()
        .name(Text.of("My Category"))
        .tooltip(Text.of("This displays when you hover over a category button")) // optional
        .group(OptionGroup.createBuilder()
                .name(Text.of("Option Group"))
                .tooltip(Text.of("Like everything in YACL, you can have tooltips")) // optional
                .collapsed(true) // optional, default false
                .option(Option.createBuilder(boolean.class)
                        .name(Text.of("My Boolean Option"))
                        .tooltip(Text.of("This option displays the basic capabilities of YetAnotherConfigLib")) // optional
                        .binding(
                                true, // default
                                () -> this.booleanToggle, // getter
                                newValue -> this.booleanToggle = newValue // setter
                        )
                        .controller(BooleanController::new)
                        .build())
                .build())
        .build()
```

So, if we look at this in-game...

![option group example](https://user-images.githubusercontent.com/43245524/188280006-74aa192b-cdf5-496d-8f6e-d891e2f45b5d.png)

#### Lists

There is another type of option called a `ListOption`. It works with all controllers and all list types that has a controller type for it. Lists take a hybrid form of option groups and a regular option, and such you add lists with `.group()`, NOT `.option()`.

You can minimize like a group and add flags like an option, it's both! Lists require an initial value for when users add another entry.

```java
ListOption.createBuilder(String.class)
    .name(Text.of("List Option"))
    .binding(/* gets and sets a List, requires list field to be not final, does not manipulate the list */)
    .controller(StringController::new) // usual controllers, passed to every entry
    .initial("") // when adding a new entry to the list, this is the initial value it has
    .build()
```

![list example](https://user-images.githubusercontent.com/43245524/206925713-115d5737-19c5-4469-894c-710f6fc271cd.png)

#### Available Flag

You can mark options as unavailable on build to prevent changing the value.

```java
Option.createBuilder(boolean.class)
        /* option things */
        .available(false)
        .build()
```

Additionally, you can modify this value after building the option with `option.setAvailable(false)`. You can do this while the user is in the UI and it will dynamically change.

![](https://i.imgur.com/CzVtXpG.png)

#### Option Flags

Options can be marked with flags that have an associated runnable that is ran when the option is saved. Can be used to reload chunks, require a restart etc.

There are some builtin flags to use which are listed below:

* `OptionFlag.GAME_RESTART` - Opens a `Screen` asking the user to restart Minecraft
* `OptionFlag.RELOAD_CHUNKS` - Reloads the world renderer
* `OptionFlag.WORLD_RENDER_UPDATE` - Rebuilds terrain
* `OptionFlag.ASSET_RELOAD` - Reloads all assets

```java
Option.createBuilder(boolean.class)
        /* option things */
        .flag(OptionFlag.GAME_RESTART)
        .build()
```

Please note if you are to use the same custom flag more than once it should be defined as a field or an interface, not in lambda form. This allows YACL to identify them as the same so they are only ran once.

#### Dynamic Tooltips

You can also make tooltips change based on the value of the option. It is as simple as consuming the value in the builder...

```java
Option.createBuilder(boolean.class)
        .tooltip(value -> Text.of("I now know that my option is set to " + value + "!"))
        .build()
```

#### Button "Options"

A thing I noticed while using other config libraries is that it is way too hard to just make a custom button that a user can press next to all the other options, so I made it super easy! This time, you don't need a binding! See here about how to customize the action controller text.

```java
ButtonOption.createBuilder()
        .name(Text.of("Pressable Button"))
        .tooltip(Text.of("This is so easy!")) // optional
        .action((yaclScreen, buttonOption) -> {
            System.out.println("Button has been pressed!");
        })
        .controller(ActionController::new)
        .build()
```

![button option](https://user-images.githubusercontent.com/43245524/188097468-326d3a56-bed7-43bb-91f2-0fcc449313cf.png)

#### Placeholder Categories

Placeholder categories can be used in place of a `ConfigCategory`. Rather than changing the option list to the category's options/groups, it just opens up another `Screen`.

```java
PlaceholderCategory.createBuilder()
        .name(Text.of("Category Name"))
        .tooltip(Text.of("Tooltip for this category!"))
        .screen((client, parent) -> new MyScreen(parent))
        .build()
```

#### Instant Option Application

You can also specify options to instantly apply to their bindings as the user changes it, skipping the `Apply Changes` button altogether. Note that this does prevent the user from being able to undo their actions and you from using option flags

```java
Option.createBuilder(int.class)
        /* option stuff! */
        .instant(true)
        .build()
```
