- Changed the layout of save/discard/leave prompts
- Leaving with unsaved changes now gives you the option to save
- Config tooltips now use standard Create tooltip splitting
This commit is contained in:
simibubi 2021-06-09 13:52:52 +02:00
parent 911aec5a3f
commit 7fae3e4968
3 changed files with 96 additions and 54 deletions

View file

@ -4,6 +4,7 @@ import java.awt.Color;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -25,6 +26,7 @@ import com.simibubi.create.foundation.gui.DelegatedStencilElement;
import com.simibubi.create.foundation.gui.ScreenOpener; import com.simibubi.create.foundation.gui.ScreenOpener;
import com.simibubi.create.foundation.gui.Theme; import com.simibubi.create.foundation.gui.Theme;
import com.simibubi.create.foundation.gui.UIRenderHelper; import com.simibubi.create.foundation.gui.UIRenderHelper;
import com.simibubi.create.foundation.gui.ConfirmationScreen.Response;
import com.simibubi.create.foundation.gui.widgets.BoxWidget; import com.simibubi.create.foundation.gui.widgets.BoxWidget;
import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
@ -161,8 +163,8 @@ public class SubMenuConfigScreen extends ConfigScreen {
.withPadding(2, 2) .withPadding(2, 2)
.withCallback((x, y) -> .withCallback((x, y) ->
new ConfirmationScreen() new ConfirmationScreen()
.at(x, y) .centered()
.withText(ITextProperties.plain("You are about to reset all settings for the " + type.toString() + " config. Are you sure?")) .withText(ITextProperties.plain("Resetting all settings of the " + type.toString() + " config. Are you sure?"))
.withAction(success -> { .withAction(success -> {
if (success) if (success)
resetConfig(spec.getValues()); resetConfig(spec.getValues());
@ -172,7 +174,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
resetAll.showingElement(AllIcons.I_CONFIG_RESET.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(resetAll))); resetAll.showingElement(AllIcons.I_CONFIG_RESET.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(resetAll)));
resetAll.getToolTip().add(new StringTextComponent("Reset All")); resetAll.getToolTip().add(new StringTextComponent("Reset All"));
resetAll.getToolTip().addAll(TooltipHelper.cutStringTextComponent("Click here to reset all configs to their default value.", TextFormatting.GRAY, TextFormatting.GRAY)); resetAll.getToolTip().addAll(TooltipHelper.cutStringTextComponent("Click here to reset all settings to their default value.", TextFormatting.GRAY, TextFormatting.GRAY));
saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20) saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20)
.withPadding(2, 2) .withPadding(2, 2)
@ -181,8 +183,8 @@ public class SubMenuConfigScreen extends ConfigScreen {
return; return;
new ConfirmationScreen() new ConfirmationScreen()
.at(x, y) .centered()
.withText(ITextProperties.plain("You are about to change " + changes.size() + " value" + (changes.size() != 1 ? "s" : "") + ". Are you sure?")) .withText(ITextProperties.plain("Saving " + changes.size() + " changed value" + (changes.size() != 1 ? "s" : "") + ""))
.withAction(success -> { .withAction(success -> {
if (success) if (success)
saveChanges(); saveChanges();
@ -200,8 +202,8 @@ public class SubMenuConfigScreen extends ConfigScreen {
return; return;
new ConfirmationScreen() new ConfirmationScreen()
.at(x, y) .centered()
.withText(ITextProperties.plain("You are about to discard " + changes.size() + " unsaved change" + (changes.size() != 1 ? "s" : "") + ". Are you sure?")) .withText(ITextProperties.plain("Discarding " + changes.size() + " unsaved change" + (changes.size() != 1 ? "s" : "") + ""))
.withAction(success -> { .withAction(success -> {
if (success) if (success)
clearChanges(); clearChanges();
@ -282,7 +284,7 @@ public class SubMenuConfigScreen extends ConfigScreen {
stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, red)); stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, red));
serverLocked.withBorderColors(red); serverLocked.withBorderColors(red);
serverLocked.getToolTip().add(new StringTextComponent("Locked").formatted(TextFormatting.BOLD)); serverLocked.getToolTip().add(new StringTextComponent("Locked").formatted(TextFormatting.BOLD));
serverLocked.getToolTip().addAll(TooltipHelper.cutStringTextComponent("You don't have enough permissions to edit the server config. You can still look at the current values here though.", TextFormatting.GRAY, TextFormatting.GRAY)); serverLocked.getToolTip().addAll(TooltipHelper.cutStringTextComponent("You do not have enough permissions to edit the server config. You can still look at the current values here though.", TextFormatting.GRAY, TextFormatting.GRAY));
} else { } else {
stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_UNLOCKED.draw(ms, 0, 0)); stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_UNLOCKED.draw(ms, 0, 0));
stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, green)); stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, green));
@ -338,24 +340,23 @@ public class SubMenuConfigScreen extends ConfigScreen {
} }
private void attemptBackstep() { private void attemptBackstep() {
if (!changes.isEmpty() && parent instanceof BaseConfigScreen) { if (changes.isEmpty() || !(parent instanceof BaseConfigScreen)) {
new ConfirmationScreen()
.centered()
.addText(ITextProperties.plain("You still have " + changes.size() + " unsaved change" + (changes.size() != 1 ? "s" : "") + " for this config."))
.addText(ITextProperties.plain("Leaving this screen will discard them without saving. Are you sure?"))
.withAction(success -> {
if (!success)
return;
changes.clear();
ScreenOpener.open(parent);
})
.open(this);
} else {
ScreenOpener.open(parent); ScreenOpener.open(parent);
return;
} }
Consumer<ConfirmationScreen.Response> action = success -> {
if (success == Response.Cancel)
return;
if (success == Response.Confirm)
saveChanges();
changes.clear();
ScreenOpener.open(parent);
};
showLeavingPrompt(action);
} }
@Override @Override
public void onClose() { public void onClose() {
if (changes.isEmpty()) { if (changes.isEmpty()) {
@ -364,17 +365,24 @@ public class SubMenuConfigScreen extends ConfigScreen {
return; return;
} }
new ConfirmationScreen() Consumer<ConfirmationScreen.Response> action = success -> {
.centered() if (success == Response.Cancel)
.addText(ITextProperties.plain("You still have " + changes.size() + " unsaved change" + (changes.size() != 1 ? "s" : "") + " for this config.")) return;
.addText(ITextProperties.plain("Leaving this screen will discard them without saving. Are you sure?")) if (success == Response.Confirm)
.withAction(success -> { saveChanges();
if (!success) changes.clear();
return; super.onClose();
};
changes.clear();
super.onClose(); showLeavingPrompt(action);
})
.open(this);
} }
public void showLeavingPrompt(Consumer<ConfirmationScreen.Response> action) {
new ConfirmationScreen().centered()
.addText(ITextProperties.plain("Leaving with " + changes.size() + " unsaved change"
+ (changes.size() != 1 ? "s" : "") + " for this config"))
.withThreeActions(action)
.open(this);
}
} }

View file

@ -17,6 +17,7 @@ import com.simibubi.create.foundation.config.ui.ConfigScreenList;
import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.DelegatedStencilElement; import com.simibubi.create.foundation.gui.DelegatedStencilElement;
import com.simibubi.create.foundation.gui.widgets.BoxWidget; import com.simibubi.create.foundation.gui.widgets.BoxWidget;
import com.simibubi.create.foundation.item.TooltipHelper;
import net.minecraft.util.text.IFormattableTextComponent; import net.minecraft.util.text.IFormattableTextComponent;
import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.StringTextComponent;
@ -52,7 +53,7 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
listeners.add(resetButton); listeners.add(resetButton);
List<String> path = value.getPath(); List<String> path = value.getPath();
labelTooltip.add(new StringTextComponent(path.get(path.size()-1)).formatted(TextFormatting.GRAY)); labelTooltip.add(new StringTextComponent(label).formatted(TextFormatting.WHITE));
String comment = spec.getComment(); String comment = spec.getComment();
if (comment == null || comment.isEmpty()) if (comment == null || comment.isEmpty())
return; return;
@ -76,8 +77,13 @@ public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
u = "in SU"; u = "in SU";
unit = u; unit = u;
} }
//add comment to tooltip // add comment to tooltip
labelTooltip.addAll(Arrays.stream(commentLines).map(StringTextComponent::new).collect(Collectors.toList())); labelTooltip.addAll(Arrays.stream(commentLines)
.map(StringTextComponent::new)
.flatMap(stc -> TooltipHelper.cutTextComponent(stc, TextFormatting.GRAY, TextFormatting.GRAY)
.stream())
.collect(Collectors.toList()));
labelTooltip.add(new StringTextComponent(ConfigScreen.modID + ":" + path.get(path.size()-1)).formatted(TextFormatting.DARK_GRAY));
} }
@Override @Override

View file

@ -12,6 +12,7 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.gui.widgets.BoxWidget; import com.simibubi.create.foundation.gui.widgets.BoxWidget;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.shader.Framebuffer; import net.minecraft.client.shader.Framebuffer;
import net.minecraft.util.text.ITextProperties; import net.minecraft.util.text.ITextProperties;
@ -20,17 +21,23 @@ import net.minecraft.util.text.Style;
public class ConfirmationScreen extends AbstractSimiScreen { public class ConfirmationScreen extends AbstractSimiScreen {
private Screen source; private Screen source;
private Consumer<Boolean> action = _success -> {}; private Consumer<Response> action = _success -> {};
private List<ITextProperties> text = new ArrayList<>(); private List<ITextProperties> text = new ArrayList<>();
private boolean centered = false; private boolean centered = false;
private int x; private int x;
private int y; private int y;
private int textWidth; private int textWidth;
private int textHeight; private int textHeight;
private boolean tristate;
private BoxWidget confirm; private BoxWidget confirm;
private BoxWidget confirmDontSave;
private BoxWidget cancel; private BoxWidget cancel;
private BoxElement textBackground; private BoxElement textBackground;
public enum Response {
Confirm, ConfirmDontSave, Cancel
}
/* /*
* Removes text lines from the back of the list * Removes text lines from the back of the list
@ -70,7 +77,13 @@ public class ConfirmationScreen extends AbstractSimiScreen {
} }
public ConfirmationScreen withAction(Consumer<Boolean> action) { public ConfirmationScreen withAction(Consumer<Boolean> action) {
this.action = r -> action.accept(r == Response.Confirm);
return this;
}
public ConfirmationScreen withThreeActions(Consumer<Response> action) {
this.action = action; this.action = action;
this.tristate = true;
return this; return this;
} }
@ -115,32 +128,46 @@ public class ConfirmationScreen extends AbstractSimiScreen {
y = height - textHeight - 30; y = height - textHeight - 30;
} }
TextStencilElement confirmText = new TextStencilElement(client.fontRenderer, "Confirm").centered(true, true); int buttonX = x + textWidth / 2 - 6 - (int) (70 * (tristate ? 1.5f : 1));
confirm = new BoxWidget(x + 4, y + textHeight + 2 , textWidth/2 - 10, 20)
.withCallback(() -> accept(true)); TextStencilElement confirmText =
new TextStencilElement(client.fontRenderer, tristate ? "Save" : "Confirm").centered(true, true);
confirm = new BoxWidget(buttonX, y + textHeight + 6, 70, 16).withCallback(() -> accept(Response.Confirm));
confirm.showingElement(confirmText.withElementRenderer(BoxWidget.gradientFactory.apply(confirm))); confirm.showingElement(confirmText.withElementRenderer(BoxWidget.gradientFactory.apply(confirm)));
widgets.add(confirm);
buttonX += 12 + 70;
if (tristate) {
TextStencilElement confirmDontSaveText =
new TextStencilElement(client.fontRenderer, "Don't Save").centered(true, true);
confirmDontSave =
new BoxWidget(buttonX, y + textHeight + 6, 70, 16).withCallback(() -> accept(Response.ConfirmDontSave));
confirmDontSave.showingElement(
confirmDontSaveText.withElementRenderer(BoxWidget.gradientFactory.apply(confirmDontSave)));
widgets.add(confirmDontSave);
buttonX += 12 + 70;
}
TextStencilElement cancelText = new TextStencilElement(client.fontRenderer, "Cancel").centered(true, true); TextStencilElement cancelText = new TextStencilElement(client.fontRenderer, "Cancel").centered(true, true);
cancel = new BoxWidget(x + textWidth/2 + 6, y + textHeight + 2, textWidth/2 - 10, 20) cancel = new BoxWidget(buttonX, y + textHeight + 6, 70, 16)
.withCallback(() -> accept(false)); .withCallback(() -> accept(Response.Cancel));
cancel.showingElement(cancelText.withElementRenderer(BoxWidget.gradientFactory.apply(cancel))); cancel.showingElement(cancelText.withElementRenderer(BoxWidget.gradientFactory.apply(cancel)));
widgets.add(confirm);
widgets.add(cancel); widgets.add(cancel);
textBackground = new BoxElement() textBackground = new BoxElement()
.gradientBorder(Theme.p(Theme.Key.BUTTON_DISABLE)) .gradientBorder(Theme.p(Theme.Key.BUTTON_DISABLE))
.withBounds(textWidth, textHeight) .withBounds(width + 10, textHeight + 35)
.at(x, y); .at(-5, y - 5);
} }
@Override @Override
public void onClose() { public void onClose() {
accept(false); accept(Response.Cancel);
} }
private void accept(boolean success) { private void accept(Response success) {
client.currentScreen = source; client.currentScreen = source;
action.accept(success); action.accept(success);
} }
@ -157,11 +184,12 @@ public class ConfirmationScreen extends AbstractSimiScreen {
for (ITextProperties line : text) { for (ITextProperties line : text) {
lineY = lineY + offset; lineY = lineY + offset;
if (line == null) if (line == null)
continue; continue;
int textX = x;
client.fontRenderer.draw(ms, line.getString(), x, lineY, 0xeaeaea); if (text.size() == 1)
x = (width - client.fontRenderer.getWidth(line)) / 2;
client.fontRenderer.draw(ms, line.getString(), textX, lineY, 0xeaeaea);
} }
ms.pop(); ms.pop();
@ -175,7 +203,7 @@ public class ConfirmationScreen extends AbstractSimiScreen {
ms.push(); ms.push();
UIRenderHelper.framebuffer.bindFramebuffer(true); UIRenderHelper.framebuffer.bindFramebuffer(true);
source.render(ms, mouseX, mouseY, 10); source.render(ms, 0, 0, 10); // zero mouse coords to prevent further tooltips
UIRenderHelper.framebuffer.unbindFramebuffer(); UIRenderHelper.framebuffer.unbindFramebuffer();
Framebuffer mainBuffer = Minecraft.getInstance().getFramebuffer(); Framebuffer mainBuffer = Minecraft.getInstance().getFramebuffer();
ms.pop(); ms.pop();