diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/DoubleSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/DoubleSettingGui.java index 94a6112..3857922 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/DoubleSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/DoubleSettingGui.java @@ -5,6 +5,7 @@ import com.github.stefvanschie.inventoryframework.pane.PatternPane; import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import io.delilaheve.CustomAnvil; import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -14,18 +15,25 @@ import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; +import xyz.alexcrea.cuanvil.util.CasedStringUtil; import xyz.alexcrea.cuanvil.util.MetricsUtil; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; public class DoubleSettingGui extends AbstractSettingGui { protected final DoubleSettingFactory holder; - protected final double before; - protected double now; - protected double step; + protected final boolean asPercentage; + @NotNull + protected final BigDecimal before; + @NotNull + protected BigDecimal now; + protected BigDecimal step; /** * Create a double setting config gui. @@ -33,10 +41,12 @@ public class DoubleSettingGui extends AbstractSettingGui { * @param holder Configuration factory of this setting. * @param now The defined value of this setting. */ - protected DoubleSettingGui(DoubleSettingFactory holder, double now) { + protected DoubleSettingGui(DoubleSettingFactory holder, @NotNull BigDecimal now, boolean asPercentage) { super(3, holder.getTitle(), holder.parent); assert holder.steps.length > 0 && holder.steps.length <= 9; this.holder = holder; + this.asPercentage = asPercentage; + this.before = now; this.now = now; this.step = holder.steps[0]; @@ -66,7 +76,7 @@ public class DoubleSettingGui extends AbstractSettingGui { ItemMeta meta = item.getItemMeta(); meta.setDisplayName("\u00A7eReset to default value"); - meta.setLore(Collections.singletonList("\u00A77Default value is: " + holder.defaultVal)); + meta.setLore(Collections.singletonList("\u00A77Default value is: " + displayValue(holder.defaultVal))); item.setItemMeta(meta); returnToDefault = new GuiItem(item, event -> { event.setCancelled(true); @@ -83,34 +93,24 @@ public class DoubleSettingGui extends AbstractSettingGui { PatternPane pane = getPane(); - // minus item - GuiItem minusItem; - if (now > holder.min) { - double planned = Math.max(holder.min, now - step); - ItemStack item = new ItemStack(Material.RED_TERRACOTTA); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName("\u00A7e" + now + " -> " + planned + " \u00A7r(\u00A7c-" + (now - planned) + "\u00A7r)"); - meta.setLore(AbstractSettingGui.CLICK_LORE); - item.setItemMeta(meta); - minusItem = new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance); + //minus item + GuiItem minusItem; + if (now.compareTo(holder.min) > 0) { + BigDecimal planned = holder.min.max(now.subtract(step)); + + minusItem = getSetValueItem(Material.RED_TERRACOTTA, planned, "\u00A7c-"); } else { minusItem = GuiGlobalItems.backgroundItem(Material.BARRIER); } pane.bindItem('-', minusItem); //plus item - // may do a function to generalise ? GuiItem plusItem; - if (now < holder.max) { - double planned = Math.min(holder.max, now + step); - ItemStack item = new ItemStack(Material.GREEN_TERRACOTTA); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName("\u00A7e" + now + " -> " + planned + " \u00A7r(\u00A7a+" + (planned - now) + "\u00A7r)"); - meta.setLore(AbstractSettingGui.CLICK_LORE); - item.setItemMeta(meta); + if (now.compareTo(holder.max) < 0) { + BigDecimal planned = holder.max.min(now.add(step)); - plusItem = new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance); + plusItem = getSetValueItem(Material.GREEN_TERRACOTTA, planned, "\u00A7a+"); } else { plusItem = GuiGlobalItems.backgroundItem(Material.BARRIER); } @@ -119,7 +119,7 @@ public class DoubleSettingGui extends AbstractSettingGui { // "result" display ItemStack resultPaper = new ItemStack(Material.PAPER); ItemMeta resultMeta = resultPaper.getItemMeta(); - resultMeta.setDisplayName("\u00A7eValue: " + now); + resultMeta.setDisplayName("\u00A7eValue: " + displayValue(now)); resultPaper.setItemMeta(resultMeta); GuiItem resultItem = new GuiItem(resultPaper, GuiGlobalActions.stayInPlace, CustomAnvil.instance); @@ -127,7 +127,7 @@ public class DoubleSettingGui extends AbstractSettingGui { // reset to default GuiItem returnToDefault; - if (now != holder.defaultVal) { + if (!now.equals(holder.defaultVal)) { returnToDefault = this.returnToDefault; } else { returnToDefault = GuiGlobalItems.backgroundItem(); @@ -137,11 +137,22 @@ public class DoubleSettingGui extends AbstractSettingGui { } + private GuiItem getSetValueItem(Material mat, BigDecimal planned, String numberPrefix){ + ItemStack item = new ItemStack(mat); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName("\u00A7e" + displayValue(now) + " -> " + displayValue(planned) + + " \u00A7r(" + numberPrefix + (displayValue(planned.subtract(now).abs()) + "\u00A7r)")); + meta.setLore(AbstractSettingGui.CLICK_LORE); + item.setItemMeta(meta); + + return new GuiItem(item, updateNowConsumer(planned), CustomAnvil.instance); + } + /** * @param planned Value to change current setting to. * @return A consumer to update the current setting's value. */ - protected Consumer updateNowConsumer(double planned) { + protected Consumer updateNowConsumer(BigDecimal planned) { return event -> { event.setCancelled(true); now = planned; @@ -199,25 +210,25 @@ public class DoubleSettingGui extends AbstractSettingGui { * @return A step item corresponding to its index value. */ protected GuiItem stepGuiItem(int stepIndex) { - double stepValue = holder.steps[stepIndex]; + BigDecimal stepValue = holder.steps[stepIndex]; // Get material properties Material stepMat; StringBuilder stepName = new StringBuilder("\u00A7"); List stepLore; Consumer clickEvent; - if (stepValue == step) { + if (Objects.equals(stepValue, step)) { stepMat = Material.GREEN_STAINED_GLASS_PANE; stepName.append('a'); - stepLore = Collections.singletonList("\u00A77Value is changing by " + stepValue); + stepLore = Collections.singletonList("\u00A77Value is changing by " + displayValue(stepValue)); clickEvent = GuiGlobalActions.stayInPlace; } else { stepMat = Material.RED_STAINED_GLASS_PANE; stepName.append('c'); - stepLore = Collections.singletonList("\u00A77Click here to change the value by " + stepValue); + stepLore = Collections.singletonList("\u00A77Click here to change the value by " + displayValue(stepValue)); clickEvent = updateStepValue(stepValue); } - stepName.append("Step of: ").append(stepValue); + stepName.append("Step of ").append(displayValue(stepValue)); // Create item stack then gui item ItemStack item = new ItemStack(stepMat); @@ -234,7 +245,7 @@ public class DoubleSettingGui extends AbstractSettingGui { * @param stepValue Value to change current step to. * @return A consumer to update the current step of this setting. */ - protected Consumer updateStepValue(double stepValue) { + protected Consumer updateStepValue(BigDecimal stepValue) { return event -> { event.setCancelled(true); this.step = stepValue; @@ -246,7 +257,7 @@ public class DoubleSettingGui extends AbstractSettingGui { @Override public boolean onSave() { - holder.config.getConfig().set(holder.configPath, now); + holder.config.getConfig().set(holder.configPath, now.doubleValue()); MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) { @@ -257,31 +268,47 @@ public class DoubleSettingGui extends AbstractSettingGui { @Override public boolean hadChange() { - return now != before; + return !now.equals(before); + } + + private static final BigDecimal PERCENTAGE_OFFSET = BigDecimal.valueOf(100); + public String displayValue(BigDecimal value){ + return displayValue(value, this.asPercentage); + } + + public static String displayValue(BigDecimal value, boolean isAsPercentage){ + if(isAsPercentage){ + return value.multiply(PERCENTAGE_OFFSET).setScale(value.scale()-2, RoundingMode.HALF_UP) + "%"; + } + return value.toString(); } /** * Create a double setting factory from setting's parameters. * - * @param title The title of the gui. - * @param parent Parent gui to go back when completed. - * @param configPath Configuration path of this setting. - * @param config Configuration holder of this setting. - * @param min Minimum value of this setting. - * @param max Maximum value of this setting. - * @param defaultVal Default value if not found on the config. - * @param steps List of step the value can increment/decrement. - * List's size should be between 1 (included) and 5 (included). - * it is visually preferable to have an odd number of step. - * If step only contain 1 value, no step item should be displayed. + * @param title The title of the gui. + * @param parent Parent gui to go back when completed. + * @param configPath Configuration path of this setting. + * @param config Configuration holder of this setting. + * @param scale The scale of the decimal. + * @param asPercentage If we should display the value as a %. + * @param min Minimum value of this setting. + * @param max Maximum value of this setting. + * @param defaultVal Default value if not found on the config. + * @param steps List of step the value can increment/decrement. + * List's size should be between 1 (included) and 5 (included). + * it is visually preferable to have an odd number of step. + * If step only contain 1 value, no step item should be displayed. * @return A factory for a double setting gui. */ public static DoubleSettingFactory doubleFactory(@NotNull String title, ValueUpdatableGui parent, - String configPath, ConfigHolder config, + String configPath, ConfigHolder config, + int scale, boolean asPercentage, double min, double max, double defaultVal, double... steps) { return new DoubleSettingFactory( title, parent, configPath, config, + scale, asPercentage, min, max, defaultVal, steps); } @@ -292,37 +319,49 @@ public class DoubleSettingGui extends AbstractSettingGui { @NotNull String title; ValueUpdatableGui parent; - double min; - double max; - double defaultVal; - double[] steps; + + int scale; + boolean asPercentage; + BigDecimal min; + BigDecimal max; + BigDecimal defaultVal; + BigDecimal[] steps; /** * Constructor for a double setting gui factory. * - * @param title The title of the gui. - * @param parent Parent gui to go back when completed. - * @param configPath Configuration path of this setting. - * @param config Configuration holder of this setting. - * @param min Minimum value of this setting. - * @param max Maximum value of this setting. - * @param defaultVal Default value if not found on the config. - * @param steps List of step the value can increment/decrement. - * List's size should be between 1 (included) and 5 (included). - * it is visually preferable to have an odd number of step. - * If step only contain 1 value, no step item should be displayed. + * @param title The title of the gui. + * @param parent Parent gui to go back when completed. + * @param configPath Configuration path of this setting. + * @param config Configuration holder of this setting. + * @param scale The scale of the decimal. + * @param asPercentage If we should display the value as a %. + * @param min Minimum value of this setting. + * @param max Maximum value of this setting. + * @param defaultVal Default value if not found on the config. + * @param steps List of step the value can increment/decrement. + * List's size should be between 1 (included) and 5 (included). + * it is visually preferable to have an odd number of step. + * If step only contain 1 value, no step item should be displayed. */ protected DoubleSettingFactory( @NotNull String title, ValueUpdatableGui parent, String configPath, ConfigHolder config, + int scale, boolean asPercentage, double min, double max, double defaultVal, double... steps) { super(configPath, config); this.title = title; this.parent = parent; - this.min = min; - this.max = max; - this.defaultVal = defaultVal; - this.steps = steps; + this.scale = scale; + this.asPercentage = asPercentage; + this.min = BigDecimal.valueOf(min).setScale(scale, RoundingMode.HALF_UP); + this.max = BigDecimal.valueOf(max).setScale(scale, RoundingMode.HALF_UP); + this.defaultVal = BigDecimal.valueOf(defaultVal).setScale(scale, RoundingMode.HALF_UP); + + this.steps = new BigDecimal[steps.length]; + for (int i = 0; i < steps.length; i++) { + this.steps[i] = BigDecimal.valueOf(steps[i]).setScale(scale, RoundingMode.HALF_UP); + } } /** @@ -336,16 +375,36 @@ public class DoubleSettingGui extends AbstractSettingGui { /** * @return The configured value for the associated setting. */ - public double getConfiguredValue() { - return this.config.getConfig().getDouble(this.configPath, this.defaultVal); + public BigDecimal getConfiguredValue() { + ConfigurationSection section = this.config.getConfig(); + if(section.isDouble(this.configPath)){ + return BigDecimal.valueOf(section.getDouble(this.configPath)).setScale(2, RoundingMode.HALF_UP); + } + return this.defaultVal; } @Override public AbstractSettingGui create() { // Get value or default - double now = getConfiguredValue(); + BigDecimal now = getConfiguredValue(); // create new gui - return new DoubleSettingGui(this, now); + return new DoubleSettingGui(this, now, this.asPercentage); + } + + + public GuiItem getItem(Material itemMat, String name){ + // Get item properties + BigDecimal value = getConfiguredValue(); + StringBuilder itemName = new StringBuilder("\u00A7a").append(name); + + return GuiGlobalItems.createGuiItemFromProperties(this, itemMat, itemName, displayValue(value, this.asPercentage)); + } + + public GuiItem getItem(Material itemMat){ + // Get item properties + String configPath = GuiGlobalItems.getConfigNameFromPath(getConfigPath()); + + return getItem(itemMat, CasedStringUtil.detectToUpperSpacedCase(configPath)); } } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java index 89ed6b6..4812d43 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiGlobalItems.java @@ -319,7 +319,7 @@ public class GuiGlobalItems { * Will not update automatically, if the setting's value change, the item need to be created again. * @return A formatted GuiItem that will create and open a GUI for the setting. */ - private static GuiItem createGuiItemFromProperties( + public static GuiItem createGuiItemFromProperties( @NotNull AbstractSettingGui.SettingGuiFactory factory, @NotNull Material itemMat, @NotNull StringBuilder itemName,