Skip to content

Commit 175aaa7

Browse files
Use Property for InventorySlotElement background
This makes InventorySlotElement backgrounds reactive, for usage in `invui-kotlin` via providers
1 parent d4a91d9 commit 175aaa7

File tree

10 files changed

+119
-11
lines changed

10 files changed

+119
-11
lines changed

invui-kotlin/src/main/kotlin/xyz/xenondevs/invui/PropertyAdapter.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import xyz.xenondevs.invui.state.MutableProperty
99
import xyz.xenondevs.invui.state.Property
1010
import java.util.function.Consumer
1111

12+
@ExperimentalReactiveApi
1213
internal class PropertyAdapter<T>(
1314
val provider: Provider<T>,
1415
val mutableView: MutableProvider<T>
@@ -55,6 +56,7 @@ internal class NonMutableMutableProvider<T>(override val identifier: Provider<T>
5556
override fun hashCode(): Int = System.identityHashCode(identifier)
5657
}
5758

59+
@ExperimentalReactiveApi
5860
internal fun <T> MutableProperty<T>.toProvider(): MutableProvider<T> {
5961
if (this is PropertyAdapter<T>)
6062
return mutableView
@@ -65,6 +67,7 @@ internal fun <T> MutableProperty<T>.toProvider(): MutableProvider<T> {
6567
return child
6668
}
6769

70+
@ExperimentalReactiveApi
6871
internal fun <T> Property<T>.toProvider(): Provider<T> {
6972
if (this is PropertyAdapter<T>)
7073
return provider

invui-kotlin/src/main/kotlin/xyz/xenondevs/invui/dsl/IngredientsDsl.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
@file:Suppress("INAPPLICABLE_JVM_NAME")
2+
@file:OptIn(ExperimentalReactiveApi::class)
3+
24
package xyz.xenondevs.invui.dsl
35

46
import org.bukkit.inventory.ItemStack
7+
import xyz.xenondevs.commons.provider.Provider
8+
import xyz.xenondevs.invui.ExperimentalReactiveApi
59
import xyz.xenondevs.invui.gui.Gui
610
import xyz.xenondevs.invui.gui.IngredientPreset
711
import xyz.xenondevs.invui.gui.Marker
@@ -10,6 +14,7 @@ import xyz.xenondevs.invui.gui.ScrollGui
1014
import xyz.xenondevs.invui.gui.Slot
1115
import xyz.xenondevs.invui.gui.SlotElement
1216
import xyz.xenondevs.invui.gui.TabGui
17+
import xyz.xenondevs.invui.gui.addIngredient
1318
import xyz.xenondevs.invui.inventory.Inventory
1419
import xyz.xenondevs.invui.item.Item
1520
import xyz.xenondevs.invui.item.ItemProvider
@@ -33,6 +38,8 @@ sealed interface IngredientsDsl {
3338

3439
infix fun Char.by(itemProvider: ItemProvider)
3540

41+
infix fun Char.by(itemProvider: Provider<ItemProvider>)
42+
3643
infix fun Char.by(itemStack: ItemStack)
3744

3845
infix fun Char.by(element: SlotElement)
@@ -112,6 +119,10 @@ internal open class IngredientsDslImpl(
112119
ingredients.addIngredient(this, itemProvider)
113120
}
114121

122+
override fun Char.by(itemProvider: Provider<ItemProvider>) {
123+
ingredients.addIngredient(this, itemProvider)
124+
}
125+
115126
override fun Char.by(itemStack: ItemStack) {
116127
ingredients.addIngredient(this, itemStack)
117128
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package xyz.xenondevs.invui.gui
2+
3+
import xyz.xenondevs.commons.provider.Provider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
import xyz.xenondevs.invui.PropertyAdapter
6+
import xyz.xenondevs.invui.inventory.Inventory
7+
import xyz.xenondevs.invui.item.Item
8+
import xyz.xenondevs.invui.item.ItemProvider
9+
import xyz.xenondevs.invui.item.setItemProvider
10+
11+
@ExperimentalReactiveApi
12+
fun <S : IngredientMapper<S>> IngredientMapper<S>.addIngredient(key: Char, provider: Provider<ItemProvider>): S =
13+
addIngredient(key, Item.builder().setItemProvider(provider).build())
14+
15+
@ExperimentalReactiveApi
16+
fun <S : IngredientMapper<S>> IngredientMapper<S>.addIngredient(key: Char, inventory: Inventory, background: Provider<ItemProvider>, offset: Int = 0): S =
17+
addIngredient(key, inventory, PropertyAdapter(background), offset)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package xyz.xenondevs.invui.gui
2+
3+
import xyz.xenondevs.commons.provider.Provider
4+
import xyz.xenondevs.invui.ExperimentalReactiveApi
5+
import xyz.xenondevs.invui.PropertyAdapter
6+
import xyz.xenondevs.invui.inventory.Inventory
7+
import xyz.xenondevs.invui.item.ItemProvider
8+
9+
@ExperimentalReactiveApi
10+
fun InventoryLink(inventory: Inventory, slot: Int, background: Provider<ItemProvider>): SlotElement.InventoryLink =
11+
SlotElement.InventoryLink(inventory, slot, PropertyAdapter(background))

invui-kotlin/src/test/kotlin/xyz/xenondevs/invui/PropertyAdapterTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:OptIn(ExperimentalReactiveApi::class)
2+
13
package xyz.xenondevs.invui
24

35
import org.junit.jupiter.api.Test

invui/src/main/java/xyz/xenondevs/invui/gui/Gui.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import xyz.xenondevs.invui.item.ItemProvider;
1313
import xyz.xenondevs.invui.item.ItemWrapper;
1414
import xyz.xenondevs.invui.state.MutableProperty;
15+
import xyz.xenondevs.invui.state.Property;
1516
import xyz.xenondevs.invui.window.Window;
1617

1718
import java.util.Collection;
@@ -400,7 +401,7 @@ static Gui single(Inventory inventory, int slot, ItemProvider background) {
400401
* @see #applyStructure(Structure)
401402
*/
402403
default void setInventory(char key, Inventory inventory) {
403-
setSlotElement(key, new InventorySlotElementSupplier(inventory, null, 0));
404+
setSlotElement(key, new InventorySlotElementSupplier(inventory, Property.of(null), 0));
404405
}
405406

406407
/**
@@ -412,7 +413,7 @@ default void setInventory(char key, Inventory inventory) {
412413
* @param offset The slot offset inside the {@link Inventory} to start from
413414
*/
414415
default void setInventory(char key, Inventory inventory, int offset) {
415-
setSlotElement(key, new InventorySlotElementSupplier(inventory, null, offset));
416+
setSlotElement(key, new InventorySlotElementSupplier(inventory, Property.of(null), offset));
416417
}
417418

418419
/**
@@ -425,7 +426,7 @@ default void setInventory(char key, Inventory inventory, int offset) {
425426
* @see #applyStructure(Structure)
426427
*/
427428
default void setInventory(char key, Inventory inventory, @Nullable ItemProvider background) {
428-
setSlotElement(key, new InventorySlotElementSupplier(inventory, background, 0));
429+
setSlotElement(key, new InventorySlotElementSupplier(inventory, Property.of(background), 0));
429430
}
430431

431432
/**
@@ -438,7 +439,7 @@ default void setInventory(char key, Inventory inventory, @Nullable ItemProvider
438439
* @param offset The slot offset inside the {@link Inventory} to start from
439440
*/
440441
default void setInventory(char key, Inventory inventory, @Nullable ItemProvider background, int offset) {
441-
setSlotElement(key, new InventorySlotElementSupplier(inventory, background, offset));
442+
setSlotElement(key, new InventorySlotElementSupplier(inventory, Property.of(background), offset));
442443
}
443444

444445
/**

invui/src/main/java/xyz/xenondevs/invui/gui/IngredientMapper.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import xyz.xenondevs.invui.item.Item;
77
import xyz.xenondevs.invui.item.ItemProvider;
88
import xyz.xenondevs.invui.item.ItemWrapper;
9+
import xyz.xenondevs.invui.state.Property;
910

1011
import java.util.function.Supplier;
1112

@@ -99,7 +100,7 @@ default S addIngredient(char key, Inventory inventory) {
99100
* @return This {@link IngredientMapper}
100101
*/
101102
default S addIngredient(char key, Inventory inventory, int offset) {
102-
return addIngredient(key, inventory, null, offset);
103+
return addIngredient(key, inventory, (ItemProvider) null, offset);
103104
}
104105

105106
/**
@@ -124,6 +125,31 @@ default S addIngredient(char key, Inventory inventory, @Nullable ItemProvider ba
124125
* @return This {@link IngredientMapper}
125126
*/
126127
default S addIngredient(char key, Inventory inventory, @Nullable ItemProvider background, int offset) {
128+
return addIngredient(key, inventory, Property.of(background), offset);
129+
}
130+
131+
/**
132+
* Adds a {@link Inventory} ingredient under the given key.
133+
*
134+
* @param key The key of the ingredient
135+
* @param inventory The {@link Inventory} ingredient
136+
* @param background The background {@link ItemProvider} {@link Property} for the {@link Inventory}
137+
* @return This {@link IngredientMapper}
138+
*/
139+
default S addIngredient(char key, Inventory inventory, Property<@Nullable ItemProvider> background) {
140+
return addIngredient(key, inventory, background, 0);
141+
}
142+
143+
/**
144+
* Adds a {@link Inventory} ingredient with the given offset and background under the given key.
145+
*
146+
* @param key The key of the ingredient
147+
* @param inventory The {@link Inventory} ingredient
148+
* @param background The background {@link ItemProvider} {@link Property} for the {@link Inventory}
149+
* @param offset The slot offset inside the {@link Inventory} to start from
150+
* @return This {@link IngredientMapper}
151+
*/
152+
default S addIngredient(char key, Inventory inventory, Property<@Nullable ItemProvider> background, int offset) {
127153
return addIngredient(key, new InventorySlotElementSupplier(inventory, background, offset));
128154
}
129155

invui/src/main/java/xyz/xenondevs/invui/gui/InventorySlotElementSupplier.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
import org.jspecify.annotations.Nullable;
44
import xyz.xenondevs.invui.inventory.Inventory;
55
import xyz.xenondevs.invui.item.ItemProvider;
6+
import xyz.xenondevs.invui.state.Property;
67

78
import java.util.ArrayList;
89
import java.util.List;
910

1011
class InventorySlotElementSupplier implements SlotElementSupplier {
1112

1213
private final Inventory inventory;
13-
private final @Nullable ItemProvider background;
14+
private final Property<@Nullable ItemProvider> background;
1415
private final int offset;
1516

16-
public InventorySlotElementSupplier(Inventory inventory, @Nullable ItemProvider background, int offset) {
17+
public InventorySlotElementSupplier(Inventory inventory, Property<@Nullable ItemProvider> background, int offset) {
1718
if (inventory.getSize() <= 0)
1819
throw new IllegalArgumentException("Illegal inventory size: " + inventory.getSize());
1920
if (offset >= inventory.getSize())

invui/src/main/java/xyz/xenondevs/invui/gui/SlotElement.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import xyz.xenondevs.invui.i18n.Languages;
1111
import xyz.xenondevs.invui.inventory.Inventory;
1212
import xyz.xenondevs.invui.item.ItemProvider;
13+
import xyz.xenondevs.invui.state.Property;
1314

1415
import java.util.ArrayList;
1516
import java.util.Collections;
@@ -105,9 +106,11 @@ public int getUpdatePeriod() {
105106
*
106107
* @param inventory The {@link Inventory} to link to
107108
* @param slot The slot in the {@link Inventory} to link to
108-
* @param background The {@link ItemProvider} to use as background if the slot is empty
109+
* @param backgroundProperty The property containing the {@link ItemProvider} to use as background if the linked slot is empty.
109110
*/
110-
record InventoryLink(Inventory inventory, int slot, @Nullable ItemProvider background) implements SlotElement {
111+
record InventoryLink(Inventory inventory, int slot,
112+
Property<@Nullable ItemProvider> backgroundProperty) implements SlotElement
113+
{
111114

112115
/**
113116
* Creates a new {@link InventoryLink} using the given {@link Inventory} and slot.
@@ -116,12 +119,33 @@ record InventoryLink(Inventory inventory, int slot, @Nullable ItemProvider backg
116119
* @param slot The slot in the {@link Inventory} to link to
117120
*/
118121
public InventoryLink(Inventory inventory, int slot) {
119-
this(inventory, slot, null);
122+
this(inventory, slot, (ItemProvider) null);
123+
}
124+
125+
/**
126+
* Creates a new {@link InventoryLink} using the given {@link Inventory}, slot and background {@link ItemProvider}.
127+
*
128+
* @param inventory The {@link Inventory} to link to
129+
* @param slot The slot in the {@link Inventory} to link to
130+
* @param background The {@link ItemProvider} to use as background if the linked slot is empty.
131+
*/
132+
public InventoryLink(Inventory inventory, int slot, @Nullable ItemProvider background) {
133+
this(inventory, slot, Property.of(background));
134+
}
135+
136+
/**
137+
* Gets the background {@link ItemProvider}.
138+
*
139+
* @return The background {@link ItemProvider}
140+
*/
141+
public @Nullable ItemProvider background() {
142+
return backgroundProperty().get();
120143
}
121144

122145
@Override
123146
public @Nullable ItemStack getItemStack(Player player) {
124147
ItemStack itemStack = inventory.getUnsafeItem(slot);
148+
ItemProvider background = backgroundProperty().get();
125149
if (itemStack == null && background != null)
126150
itemStack = background.get(Languages.getInstance().getLocale(player));
127151
return itemStack;
@@ -135,11 +159,13 @@ public SlotElement getHoldingElement() {
135159
@Override
136160
public void addObserver(Observer who, int how) {
137161
inventory.addObserver(who, slot, how);
162+
backgroundProperty.observeWeak(this, thisRef -> thisRef.inventory.notifyWindows(slot));
138163
}
139164

140165
@Override
141166
public void removeObserver(Observer who, int how) {
142167
inventory.removeObserver(who, slot, how);
168+
backgroundProperty.unobserveWeak(this);
143169
}
144170

145171
@Override

invui/src/test/java/xyz/xenondevs/invui/Utils.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class Utils {
1313
public static void assertSlotElements(Gui gui, @Nullable SlotElement... elements) {
1414
assertEquals(gui.getSize(), elements.length);
1515
for (int i = 0; i < elements.length; i++) {
16-
assertEquals(elements[i], gui.getSlotElement(i), "i=" + i);
16+
assertSlotElementEquals(elements[i], gui.getSlotElement(i), "i=" + i);
1717
}
1818
}
1919

@@ -30,6 +30,16 @@ public static void assertItems(Gui gui, @Nullable Item... items) {
3030
}
3131
}
3232

33+
public static void assertSlotElementEquals(SlotElement expected, SlotElement actual, String message) {
34+
if (expected instanceof SlotElement.InventoryLink el && actual instanceof SlotElement.InventoryLink al) {
35+
assertEquals(el.inventory(), al.inventory(), message);
36+
assertEquals(el.slot(), al.slot(), message);
37+
assertEquals(el.background(), al.background(), message);
38+
} else {
39+
assertEquals(expected, actual, message);
40+
}
41+
}
42+
3343
public static SlotElement.InventoryLink il(Inventory inventory, int slot) {
3444
return new SlotElement.InventoryLink(inventory, slot);
3545
}

0 commit comments

Comments
 (0)