From cc92fbb2bb7746b3e7a5bd27d0cd59ecd62ffa97 Mon Sep 17 00:00:00 2001 From: hnOsmium0001 <36975818+hnOsmium0001@users.noreply.github.com> Date: Mon, 30 Mar 2020 12:54:45 -0700 Subject: [PATCH 1/3] Initial conversion to tool panel --- .../library/gui/RenderingHelper.java | 7 + .../library/gui/ScissorTest.java | 2 - .../library/gui/window/Dialog.java | 38 ++-- .../ui/manager/FactoryManagerGUI.java | 12 +- .../ui/manager/editor/EditorPanel.java | 8 +- .../ui/manager/editor/FlowComponent.java | 180 +++--------------- .../stevesfactory/ui/manager/editor/Menu.java | 12 +- .../ui/manager/editor/OffsetText.java | 19 +- .../ui/manager/editor/PropertyManager.java | 4 +- .../ui/manager/menu/InvocationTargetMenu.java | 2 +- .../ui/manager/selection/SelectionPanel.java | 2 +- .../{ToolPanel.java => ToolHolderPanel.java} | 10 +- .../ui/manager/tool/group/GroupButton.java | 38 ++-- .../ui/manager/tool/group/GroupDataModel.java | 4 +- .../ui/manager/tool/group/Grouplist.java | 16 +- .../ui/manager/tool/inspector/Inspector.java | 78 ++++++++ .../tool/inspector/PropertiesPanel.java | 44 +++++ .../manager/tool/inspector/StatusPanel.java | 59 ++++++ .../{IconToolType.java => ToolboxEntry.java} | 11 +- .../ui/manager/toolbox/ToolboxPanel.java | 22 ++- src/main/resources/assets/sfm/lang/en_us.json | 48 ++--- .../sfm/textures/gui/flow_components.png | Bin 26262 -> 11136 bytes .../sfm/textures/gui/tool_icon/inspector.png | Bin 0 -> 676 bytes 23 files changed, 354 insertions(+), 262 deletions(-) rename src/main/java/vswe/stevesfactory/ui/manager/tool/{ToolPanel.java => ToolHolderPanel.java} (88%) create mode 100644 src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java create mode 100644 src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/PropertiesPanel.java create mode 100644 src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java rename src/main/java/vswe/stevesfactory/ui/manager/toolbox/{IconToolType.java => ToolboxEntry.java} (89%) create mode 100644 src/main/resources/assets/sfm/textures/gui/tool_icon/inspector.png diff --git a/src/main/java/vswe/stevesfactory/library/gui/RenderingHelper.java b/src/main/java/vswe/stevesfactory/library/gui/RenderingHelper.java index 6b4d94451..d336c3278 100644 --- a/src/main/java/vswe/stevesfactory/library/gui/RenderingHelper.java +++ b/src/main/java/vswe/stevesfactory/library/gui/RenderingHelper.java @@ -139,6 +139,13 @@ public static void drawColorLogic(int x, int y, int width, int height, int red, RenderSystem.enableTexture(); } + public static void drawBorderedBox(int x1, int y1, int x2, int y2) { + GlStateManager.disableTexture(); + drawRect(x1, y1, x2, y2, 0xff404040); + drawRect(x1 + 1, y1 + 1, x2 - 1, y2 - 1, 0xff5e5e5e); + GlStateManager.enableTexture(); + } + public static void drawThickBeveledBox(int x1, int y1, int x2, int y2, int thickness, int topLeftColor, int bottomRightColor, int fillColor) { RenderSystem.disableTexture(); drawRect(x1, y1, x2, y2, bottomRightColor); diff --git a/src/main/java/vswe/stevesfactory/library/gui/ScissorTest.java b/src/main/java/vswe/stevesfactory/library/gui/ScissorTest.java index 96058b46c..5a41ec5b6 100644 --- a/src/main/java/vswe/stevesfactory/library/gui/ScissorTest.java +++ b/src/main/java/vswe/stevesfactory/library/gui/ScissorTest.java @@ -25,8 +25,6 @@ public final class ScissorTest { public static ScissorTest scaled(int x, int y, int width, int height) { MainWindow mainWindow = Minecraft.getInstance().getMainWindow(); double scale = mainWindow.getGuiScaleFactor(); - x += RenderingHelper.getTranslationX(); - y += RenderingHelper.getTranslationY(); return new ScissorTest((int) (x * scale), (int) (mainWindow.getHeight() - ((y + height) * scale)), (int) (width * scale), (int) (height * scale)); } diff --git a/src/main/java/vswe/stevesfactory/library/gui/window/Dialog.java b/src/main/java/vswe/stevesfactory/library/gui/window/Dialog.java index 9ebc2d4de..7498d5e74 100644 --- a/src/main/java/vswe/stevesfactory/library/gui/window/Dialog.java +++ b/src/main/java/vswe/stevesfactory/library/gui/window/Dialog.java @@ -15,31 +15,23 @@ import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.function.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.IntConsumer; +import java.util.function.Supplier; public class Dialog extends AbstractPopupWindow { - public static Dialog createPrompt(String message, BiConsumer onConfirm) { - return createPrompt(message, onConfirm, (b, t) -> {}); - } - - public static Dialog createPrompt(String message, BiConsumer onConfirm, BiConsumer onCancel) { - return createPrompt(message, "", onConfirm, onCancel); - } - - public static Dialog createPrompt(String message, String defaultText, BiConsumer onConfirm) { - return createPrompt(message, defaultText, onConfirm, (b, t) -> {}); - } - - public static Dialog createPrompt(String message, String defaultText, BiConsumer onConfirm, BiConsumer onCancel) { - return createPrompt(message, defaultText, "gui.sfm.ok", "gui.sfm.cancel", onConfirm, onCancel); - } - - public static Dialog createPrompt(String message, String defaultText, String confirm, String cancel, BiConsumer onConfirm, BiConsumer onCancel) { + public static Dialog createPrompt( + String message, + Supplier fieldProvider, + String confirm, String cancel, + BiConsumer onConfirm, + BiConsumer onCancel + ) { Dialog dialog = dialog(message); - TextField inputBox = new TextField(0, 0, 0, 16); - inputBox.setText(defaultText); + TextField inputBox = fieldProvider.get(); dialog.insertBeforeButtons(inputBox); dialog.onPostReflow = inputBox::expandHorizontally; @@ -123,8 +115,10 @@ private static Dialog dialog(String message) { private Box buttons; private List children; - public Runnable onPreReflow = () -> {}; - public Runnable onPostReflow = () -> {}; + public Runnable onPreReflow = () -> { + }; + public Runnable onPostReflow = () -> { + }; public Dialog() { this.messageBox = new TextList(10, 10, new ArrayList<>()); diff --git a/src/main/java/vswe/stevesfactory/ui/manager/FactoryManagerGUI.java b/src/main/java/vswe/stevesfactory/ui/manager/FactoryManagerGUI.java index 376e3ed17..f31d6b14b 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/FactoryManagerGUI.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/FactoryManagerGUI.java @@ -21,7 +21,7 @@ import vswe.stevesfactory.ui.manager.editor.ConnectionsPanel; import vswe.stevesfactory.ui.manager.editor.EditorPanel; import vswe.stevesfactory.ui.manager.selection.SelectionPanel; -import vswe.stevesfactory.ui.manager.tool.ToolPanel; +import vswe.stevesfactory.ui.manager.tool.ToolHolderPanel; import vswe.stevesfactory.ui.manager.tool.group.GroupDataModel; import vswe.stevesfactory.ui.manager.toolbox.ToolboxPanel; @@ -191,7 +191,7 @@ public static class TopLevelWidget extends AbstractContainer> children; @@ -200,10 +200,10 @@ private TopLevelWidget(PrimaryWindow window) { this.selectionPanel = new SelectionPanel(); this.editorPanel = new EditorPanel(); this.connectionsPanel = new ConnectionsPanel(); - this.toolPanel = new ToolPanel(); + this.toolHolderPanel = new ToolHolderPanel(); this.toolboxPanel = new ToolboxPanel(); // Let connections panel receive events first - this.children = ImmutableList.of(selectionPanel, connectionsPanel, editorPanel, toolPanel, toolboxPanel); + this.children = ImmutableList.of(selectionPanel, connectionsPanel, editorPanel, toolHolderPanel, toolboxPanel); } public void init() { @@ -250,14 +250,14 @@ public void reflow() { selectionPanel.setHeight(prevHeight); editorPanel.setHeight(prevHeight); connectionsPanel.setHeight(prevHeight); - toolPanel.setHeight(prevHeight); + toolHolderPanel.setHeight(prevHeight); toolboxPanel.setHeight(prevHeight); } selectionPanel.reflow(); editorPanel.reflow(); connectionsPanel.reflow(); - toolPanel.reflow(); + toolHolderPanel.reflow(); toolboxPanel.reflow(); DynamicWidthWidget.reflowDynamicWidth(getDimensions(), children); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java index 0e32b2db3..b4395c6be 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java @@ -301,9 +301,9 @@ public void update(float particleTicks) { private void openActionMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(FactoryManagerGUI.PASTE_ICON, "gui.sfm.FactoryManager.Editor.CtxMenu.Paste", b -> actionPaste()), - new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.CtxMenu.CleanupProcedures", b -> actionCleanup()), - new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.CtxMenu.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) + new CallbackEntry(FactoryManagerGUI.PASTE_ICON, "gui.sfm.FactoryManager.Editor.Paste", b -> actionPaste()), + new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.CleanupProcedures", b -> actionCleanup()), + new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } @@ -314,7 +314,7 @@ private void actionPaste() { try { tag = JsonToNBT.getTagFromJson(json); } catch (CommandSyntaxException e) { - Dialog.createDialog("gui.sfm.FactoryManager.Editor.Dialog.PasteProcedure.Fail").tryAddSelfToActiveGUI(); + Dialog.createDialog("gui.sfm.FactoryManager.Editor.Paste.Fail").tryAddSelfToActiveGUI(); return; } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java index 9cc96fdc8..b1becfd5f 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java @@ -1,13 +1,14 @@ package vswe.stevesfactory.ui.manager.editor; import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.renderer.RenderHelper; import net.minecraft.nbt.CompoundNBT; import vswe.stevesfactory.api.logic.Connection; import vswe.stevesfactory.api.logic.IClientDataStorage; import vswe.stevesfactory.api.logic.IProcedure; +import vswe.stevesfactory.library.gui.RenderingHelper; import vswe.stevesfactory.library.gui.TextureWrapper; import vswe.stevesfactory.library.gui.contextmenu.CallbackEntry; import vswe.stevesfactory.library.gui.contextmenu.ContextMenu; @@ -23,6 +24,7 @@ import vswe.stevesfactory.library.gui.widget.box.MinimumLinearList; import vswe.stevesfactory.library.gui.window.Dialog; import vswe.stevesfactory.ui.manager.tool.group.Grouplist; +import vswe.stevesfactory.ui.manager.tool.inspector.Inspector; import vswe.stevesfactory.utils.NetworkHelper; import javax.annotation.Nonnull; @@ -37,71 +39,6 @@ public class FlowComponent

extends AbstractContainer implements Comparable> { - public enum State { - COLLAPSED(TextureWrapper.ofFlowComponent(0, 0, 64, 20), - TextureWrapper.ofFlowComponent(0, 20, 9, 10), - TextureWrapper.ofFlowComponent(0, 30, 9, 10)), - EXPANDED(TextureWrapper.ofFlowComponent(64, 0, 124, 152), - TextureWrapper.ofFlowComponent(9, 20, 9, 10), - TextureWrapper.ofFlowComponent(9, 30, 9, 10)); - - public final TextureWrapper background; - public final TextureWrapper toggleStateNormal; - public final TextureWrapper toggleStateHovered; - - State(TextureWrapper background, TextureWrapper toggleStateNormal, TextureWrapper toggleStateHovered) { - this.background = background; - this.toggleStateNormal = toggleStateNormal; - this.toggleStateHovered = toggleStateHovered; - } - - public int componentWidth() { - return background.getPortionWidth(); - } - - public int componentHeight() { - return background.getPortionHeight(); - } - } - - public static class ToggleStateButton extends AbstractIconButton { - - public ToggleStateButton(FlowComponent parent) { - super(-1, -1, 9, 10); - setParentWidget(parent); - } - - @Override - public TextureWrapper getTextureNormal() { - return getParentWidget().getState().toggleStateNormal; - } - - @Override - public TextureWrapper getTextureHovered() { - return getParentWidget().getState().toggleStateHovered; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (button == GLFW_MOUSE_BUTTON_LEFT) { - getParentWidget().toggleState(); - return true; - } - return false; - } - - @Nonnull - @Override - public FlowComponent getParentWidget() { - return Objects.requireNonNull((FlowComponent) super.getParentWidget()); - } - - @Override - public BoxSizing getBoxSizing() { - return BoxSizing.PHANTOM; - } - } - public static class RenameButton extends AbstractIconButton { public static final TextureWrapper NORMAL = TextureWrapper.ofFlowComponent(0, 124, 9, 9); @@ -271,8 +208,8 @@ public static

FlowComponent

of(P } private P procedure; + private final MinimumLinearList> menus; - private final ToggleStateButton toggleStateButton; private final RenameButton renameButton; private final SubmitButton submitButton; private final CancelButton cancelButton; @@ -280,11 +217,9 @@ public static

FlowComponent

of(P private final ConnectionNodes inputNodes; private final ConnectionNodes outputNodes; private final ErrorIndicator errorIndicator; - private final MinimumLinearList> menus; // A list that refers to all the widgets above private final List children; - private State state; private int zIndex; // Temporary data @@ -292,14 +227,16 @@ public static

FlowComponent

of(P private int initialDragLocalY; public FlowComponent(P procedure, int amountInputs, int amountOutputs) { - super(0, 0, 0, 0); + super(0, 0, 64, 20); String name = procedure.getName(); - this.toggleStateButton = new ToggleStateButton(this); this.renameButton = new RenameButton(this); + this.renameButton.setLocation(52, 6); this.submitButton = new SubmitButton(this); + this.submitButton.setLocation(54, 3); this.cancelButton = new CancelButton(this, name); + this.cancelButton.setLocation(54, 11); // The cursor looks a bit to short (and cute) with these numbers, might want change them? - this.nameBox = new TextField(6, 8, 35, 10); + this.nameBox = new TextField(6, 8, 45, 10); this.nameBox.setBackgroundStyle(TextField.BackgroundStyle.NONE); this.nameBox.setText(name); this.nameBox.setTextColor(0xff303030, 0xff303030); @@ -308,78 +245,17 @@ public FlowComponent(P procedure, int amountInputs, int amountOutputs) { this.inputNodes = ConnectionNodes.inputNodes(amountInputs); this.outputNodes = ConnectionNodes.outputNodes(amountOutputs); this.errorIndicator = ErrorIndicator.error(); - this.menus = new MinimumLinearList<>(120, 130); - this.menus.setLocation(2, 20); - this.children = ImmutableList.of(toggleStateButton, renameButton, submitButton, cancelButton, nameBox, inputNodes, outputNodes, errorIndicator, menus); + this.menus = new MinimumLinearList<>(0, 0); + this.children = ImmutableList.of(renameButton, submitButton, cancelButton, nameBox, inputNodes, outputNodes, errorIndicator); this.setLinkedProcedure(procedure); - this.state = State.COLLAPSED; errorIndicator.setLocation(2, 8); } - public TextureWrapper getBackgroundTexture() { - return state.background; - } - - public State getState() { - return state; - } - - public void toggleState() { - switch (state) { - case COLLAPSED: - expand(); - break; - case EXPANDED: - collapse(); - break; - } - } - - public void expand() { - state = State.EXPANDED; - setDimensions(state.componentWidth(), state.componentHeight()); - - nameBox.setWidth(95); - nameBox.scrollToFront(); - toggleStateButton.setLocation(114, 5); - renameButton.setLocation(103, 6); - submitButton.setLocation(105, 3); - cancelButton.setLocation(105, 11); - renameButton.setEnabled(true); - updateMenusEnableState(true); - reflow(); - } - - public void collapse() { - state = State.COLLAPSED; - setDimensions(state.componentWidth(), state.componentHeight()); - - nameBox.setWidth(35); - nameBox.scrollToFront(); - toggleStateButton.setLocation(54, 5); - renameButton.setLocation(43, 6); - submitButton.setLocation(45, 3); - cancelButton.setLocation(45, 11); - if (isEditing()) { - cancelButton.cancel(); - } - renameButton.setEnabled(false); - updateMenusEnableState(false); - reflow(); - } - public boolean isEditing() { return submitButton.isEnabled(); } - private void updateMenusEnableState(boolean enabled) { - menus.setEnabled(enabled); - for (Menu

menu : menus.getChildren()) { - menu.setEnabled(enabled); - } - } - public String getName() { return nameBox.getText(); } @@ -414,6 +290,7 @@ public void expandAllMenus() { @Override public void reflow() { + nameBox.scrollToFront(); inputNodes.setWidth(getWidth()); inputNodes.setY(-ConnectionsPanel.REGULAR_HEIGHT); inputNodes.reflow(); @@ -452,10 +329,11 @@ public void render(int mouseX, int mouseY, float particleTicks) { RenderEventDispatcher.onPreRender(this, mouseX, mouseY); RenderSystem.color3f(1F, 1F, 1F); - getBackgroundTexture().draw(getAbsoluteX(), getAbsoluteY()); + int x = getAbsoluteX(); + int y = getAbsoluteY(); + RenderingHelper.drawBorderedBox(x, y, x + getWidth(), y + getHeight()); // Renaming state (showing different buttons at different times) is handled inside the widgets' render method - toggleStateButton.render(mouseX, mouseY, particleTicks); renameButton.render(mouseX, mouseY, particleTicks); submitButton.render(mouseX, mouseY, particleTicks); cancelButton.render(mouseX, mouseY, particleTicks); @@ -464,7 +342,6 @@ public void render(int mouseX, int mouseY, float particleTicks) { inputNodes.render(mouseX, mouseY, particleTicks); outputNodes.render(mouseX, mouseY, particleTicks); errorIndicator.render(mouseX, mouseY, particleTicks); - menus.render(mouseX, mouseY, particleTicks); if (nameBox.isInside(mouseX, mouseY)) { WidgetScreen.getCurrent().setHoveringText(getName(), mouseX, mouseY); @@ -485,6 +362,10 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } getWindow().setFocusedWidget(this); + Inspector inspector = Inspector.getActiveInspector(); + if (inspector != null) { + inspector.openFlowComponent(this); + } if (button == GLFW_MOUSE_BUTTON_LEFT) { initialDragLocalX = (int) mouseX - getAbsoluteX(); initialDragLocalY = (int) mouseY - getAbsoluteY(); @@ -575,15 +456,15 @@ private boolean isDragging() { public void setParentWidget(EditorPanel parent) { this.setParentWidget((IWidget) parent); - collapse(); + reflow(); } private void openContextMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(DELETE_ICON, "gui.sfm.FactoryManager.Editor.CtxMenu.Delete", b -> actionDelete()), - new CallbackEntry(CUT_ICON, "gui.sfm.FactoryManager.Editor.CtxMenu.Cut", b -> actionCut()), - new CallbackEntry(COPY_ICON, "gui.sfm.FactoryManager.Editor.CtxMenu.Copy", b -> actionCopy()), - new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.CtxMenu.ChangeGroup", b -> actionChangeGroup()) + new CallbackEntry(DELETE_ICON, "gui.sfm.FactoryManager.Editor.Delete", b -> actionDelete()), + new CallbackEntry(CUT_ICON, "gui.sfm.FactoryManager.Editor.Cut", b -> actionCut()), + new CallbackEntry(COPY_ICON, "gui.sfm.FactoryManager.Editor.Copy", b -> actionCopy()), + new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.ChangeGroup", b -> actionChangeGroup()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } @@ -591,7 +472,7 @@ private void openContextMenu() { private void actionDelete() { if (Screen.hasShiftDown()) { Dialog.createBiSelectionDialog( - "gui.sfm.FactoryManager.Editor.Dialog.DeleteAll.ConfirmMsg", + "gui.sfm.FactoryManager.Editor.DeleteAll.ConfirmMsg", "gui.sfm.yes", "gui.sfm.no", b -> removeGraph(this), b -> { @@ -613,11 +494,12 @@ private void actionCut() { } private void actionChangeGroup() { - Grouplist.createSelectGroupDialog(newGroup -> { - disconnect(); - setGroup(newGroup); - }, () -> { - }).tryAddSelfToActiveGUI(); + Grouplist.createSelectGroupDialog( + newGroup -> { + disconnect(); + setGroup(newGroup); + }, + () -> {}).tryAddSelfToActiveGUI(); } public void save() { diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java index aac4a5930..ff54a2726 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java @@ -143,9 +143,7 @@

addChildren(IWidget widget) { } @Override - public Menu - -

addChildren(Collection widgets) { + public Menu

addChildren(Collection widgets) { children.addAll(widgets); return this; } @@ -254,8 +252,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { getWindow().setFocusedWidget(this); if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { ImmutableList.Builder list = ImmutableList.builder() - .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.CtxMenu.CollapseAll", b -> flowComponent.collapseAllMenus())) - .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Editor.CtxMenu.ExpandAll", b -> flowComponent.expandAllMenus())); + .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Inspector.Props.CollapseAll", b -> flowComponent.collapseAllMenus())) + .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Inspector.Props.ExpandAll", b -> flowComponent.expandAllMenus())); for (Supplier entry : actionMenuEntries) { list.add(entry.get()); } @@ -276,9 +274,7 @@ protected void saveData() { @SuppressWarnings("unchecked") @Nonnull @Override - public LinearList> - - getParentWidget() { + public LinearList> getParentWidget() { return Objects.requireNonNull((LinearList>) super.getParentWidget()); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java index eabb9da20..9ac4f554e 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java @@ -3,6 +3,7 @@ import net.minecraft.client.gui.screen.Screen; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; import vswe.stevesfactory.library.gui.widget.AbstractWidget; +import vswe.stevesfactory.library.gui.widget.NumberField; import vswe.stevesfactory.library.gui.widget.mixin.LeafWidgetMixin; import vswe.stevesfactory.library.gui.window.Dialog; @@ -65,13 +66,17 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { if (Screen.hasControlDown()) { set(0); } else { - Dialog.createPrompt("gui.sfm.FactoryManager.Editor.EditOffset", (b, s) -> { - try { - set(Integer.parseInt(s)); - } catch (NumberFormatException e) { - Dialog.createDialog("gui.sfm.FactoryManager.Editor.InvalidNumberFormat").tryAddSelfToActiveGUI(); - } - }).tryAddSelfToActiveGUI(); + NumberField field = NumberField.integerField(0, 16); + field.setValue(value); + + Dialog prompt = Dialog.createPrompt( + "gui.sfm.FactoryManager.Editor.PopupMsg.EditOffset", + () -> field, + "gui.sfm.ok", "gui.sfm.cancel", + (b, s) -> { + }, + (b, s) -> set(field.getValue())); + prompt.tryAddSelfToActiveGUI(); } return true; } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/PropertyManager.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/PropertyManager.java index 1df5ce53f..4345f72fd 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/PropertyManager.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/PropertyManager.java @@ -150,8 +150,8 @@ private void updateText() { if (cachedIndex != nextIndex || cachedText == null) { Case nextCase = cases.get(nextIndex); cachedText = nextCase.hasName() - ? I18n.format("gui.sfm.FactoryManager.Editor.CtxMenu.CycleProperty.Named", nextCase.getName()) - : I18n.format("gui.sfm.FactoryManager.Editor.CtxMenu.CycleProperty"); + ? I18n.format("gui.sfm.FactoryManager.Tool.Inspector.Props.CycleProperty.Named", nextCase.getName()) + : I18n.format("gui.sfm.FactoryManager.Tool.Inspector.Props.CycleProperty"); cachedIndex = nextIndex; reflowSafe(); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/menu/InvocationTargetMenu.java b/src/main/java/vswe/stevesfactory/ui/manager/menu/InvocationTargetMenu.java index d1d83de3d..9dff5d85c 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/menu/InvocationTargetMenu.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/menu/InvocationTargetMenu.java @@ -38,7 +38,7 @@ public InvocationTargetMenu() { addChildren(options); - injectAction(() -> new CallbackEntry(null, "menu.sfm.InvocationTarget.CtxMenu.Rescan", b -> scanTargets())); + injectAction(() -> new CallbackEntry(null, "menu.sfm.InvocationTarget.Rescan", b -> scanTargets())); } @Override diff --git a/src/main/java/vswe/stevesfactory/ui/manager/selection/SelectionPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/selection/SelectionPanel.java index 8b70ef071..7dafef1a3 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/selection/SelectionPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/selection/SelectionPanel.java @@ -98,7 +98,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { private void openActionMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.CtxMenu.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) + new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/ToolPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/ToolHolderPanel.java similarity index 88% rename from src/main/java/vswe/stevesfactory/ui/manager/tool/ToolPanel.java rename to src/main/java/vswe/stevesfactory/ui/manager/tool/ToolHolderPanel.java index d428e7a8f..8828b82e9 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/ToolPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/ToolHolderPanel.java @@ -6,6 +6,7 @@ import vswe.stevesfactory.library.gui.contextmenu.ContextMenu; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; import vswe.stevesfactory.library.gui.screen.WidgetScreen; +import vswe.stevesfactory.library.gui.widget.AbstractContainer; import vswe.stevesfactory.library.gui.widget.IWidget; import vswe.stevesfactory.ui.manager.DynamicWidthWidget; import vswe.stevesfactory.ui.manager.FactoryManagerGUI; @@ -16,11 +17,11 @@ import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LEFT; import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_RIGHT; -public final class ToolPanel extends DynamicWidthWidget { +public final class ToolHolderPanel extends DynamicWidthWidget { private List children = ImmutableList.of(); - public ToolPanel() { + public ToolHolderPanel() { super(WidthOccupierType.MIN_WIDTH); } @@ -33,6 +34,9 @@ public void setActivePanel(@Nullable T panel) { panel.setX(RenderingHelper.LEFT_BORDER + 1); panel.setHeight(getHeight()); getWindow().setFocusedWidget(panel); + if (panel instanceof AbstractContainer) { + ((AbstractContainer) panel).reflow(); + } } FactoryManagerGUI.get().getTopLevel().reflow(); } @@ -81,7 +85,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { private void openContextMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.CtxMenu.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) + new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupButton.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupButton.java index f885106b7..619d8113d 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupButton.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupButton.java @@ -6,6 +6,7 @@ import vswe.stevesfactory.library.gui.contextmenu.ContextMenu; import vswe.stevesfactory.library.gui.screen.WidgetScreen; import vswe.stevesfactory.library.gui.widget.TextButton; +import vswe.stevesfactory.library.gui.widget.TextField; import vswe.stevesfactory.library.gui.window.Dialog; import vswe.stevesfactory.ui.manager.FactoryManagerGUI; @@ -40,9 +41,9 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { private void openContextMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(FactoryManagerGUI.DELETE_ICON, "gui.sfm.FactoryManager.Tool.Group.CtxMenu.Delete", b -> actionDelete()), - new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Group.CtxMenu.RenameGroup", b -> actionRename()), - new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Group.CtxMenu.MoveContent", b -> actionMoveContent()) + new CallbackEntry(FactoryManagerGUI.DELETE_ICON, "gui.sfm.FactoryManager.Tool.Group.Delete", b -> actionDelete()), + new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Group.RenameGroup", b -> actionRename()), + new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Group.MoveContent", b -> actionMoveContent()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } @@ -56,15 +57,20 @@ private void actionDelete() { } private void actionRename() { - Dialog.createPrompt("gui.sfm.FactoryManager.Tool.Group.Dialog.RenameGroup", (b, newName) -> { - for (String group : FactoryManagerGUI.get().groupModel.getGroups()) { - if (newName.equals(group)) { - Dialog.createDialog(I18n.format("gui.sfm.FactoryManager.Tool.Group.Dialog.RenameFailed", newName)).tryAddSelfToActiveGUI(); - return; - } - } - FactoryManagerGUI.get().groupModel.updateGroup(group, newName); - }).tryAddSelfToActiveGUI(); + Dialog.createPrompt( + "gui.sfm.FactoryManager.Tool.Group.RenameGroup.Prompt", + () -> new TextField(0, 0, 0, 16), + "gui.sfm.ok", "gui.sfm.cancel", + (b, newName) -> { + for (String group : FactoryManagerGUI.get().groupModel.getGroups()) { + if (newName.equals(group)) { + Dialog.createDialog(I18n.format("gui.sfm.FactoryManager.Tool.Group.RenameGroup.Failed", newName)).tryAddSelfToActiveGUI(); + return; + } + } + FactoryManagerGUI.get().groupModel.updateGroup(group, newName); + }, + (b, newName) -> {}).tryAddSelfToActiveGUI(); } private void actionMoveContent() { @@ -78,10 +84,6 @@ private void actionMoveContent() { () -> {}).tryAddSelfToActiveGUI(); } - private static Grouplist getGroupList() { - return FactoryManagerGUI.get().getTopLevel().toolboxPanel.getGroupList(); - } - public String getGroup() { return group; } @@ -101,6 +103,10 @@ public int getHoveredBorderColor() { return isSelected() ? 0xffffff00 : super.getNormalBorderColor(); } + private Grouplist getGroupList() { + return FactoryManagerGUI.get().getTopLevel().toolboxPanel.getGroupList(); + } + private boolean isSelected() { return group.equals(FactoryManagerGUI.get().groupModel.getCurrentGroup()); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupDataModel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupDataModel.java index 2ea82ed51..2c1749439 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupDataModel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/GroupDataModel.java @@ -51,8 +51,8 @@ public void removeListenerUpdate(int id) { } /** - * Add a listener for when the user reselects current group. Note that this will not be fired for the default - * selection {@link GroupDataModel#DEFAULT_GROUP}. + * Add a listener for when the user re-selects current group. Note that this will not be fired for the + * default selection {@link GroupDataModel#DEFAULT_GROUP}. */ public int addListenerSelect(Consumer listener) { selectListeners.add(listener); diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/Grouplist.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/Grouplist.java index 682fd5df7..2c451dc0d 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/group/Grouplist.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/group/Grouplist.java @@ -4,13 +4,17 @@ import vswe.stevesfactory.library.gui.RenderingHelper; import vswe.stevesfactory.library.gui.widget.Spacer; import vswe.stevesfactory.library.gui.widget.TextButton; +import vswe.stevesfactory.library.gui.widget.TextField; import vswe.stevesfactory.library.gui.widget.box.LinearList; import vswe.stevesfactory.library.gui.window.Dialog; import vswe.stevesfactory.ui.manager.FactoryManagerGUI; +import vswe.stevesfactory.ui.manager.editor.FlowComponent; import javax.annotation.Nonnull; import java.util.Collection; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; public class Grouplist extends LinearList { @@ -92,13 +96,16 @@ public void delete(String group) { public static Dialog createNewGroupDialog() { return Dialog.createPrompt( - "gui.sfm.FactoryManager.Tool.Group.Dialog.CreateGroup", + "gui.sfm.FactoryManager.Tool.Group.CreateGroup", + () -> new TextField(0, 0, 0, 16), + "gui.sfm.ok", "gui.sfm.cancel", (b, name) -> { boolean success = FactoryManagerGUI.get().groupModel.addGroup(name); if (!success) { - Dialog.createDialog("gui.sfm.FactoryManager.Tool.Group.Dialog.CreateFailed").tryAddSelfToActiveGUI(); + Dialog.createDialog("gui.sfm.FactoryManager.Tool.Group.CreateFailed").tryAddSelfToActiveGUI(); } - }); + }, + (b, name) -> {}); } public static final int SEL_DIALOG_LIST_WIDTH = 280; @@ -107,7 +114,7 @@ public static Dialog createNewGroupDialog() { public static Dialog createSelectGroupDialog(Consumer onConfirm, Runnable onCancel) { Dialog dialog = new Dialog(); - dialog.getMessageBox().addLine(I18n.format("gui.sfm.FactoryManager.Tool.Group.Dialog.SelectGroup")); + dialog.getMessageBox().addLine(I18n.format("gui.sfm.FactoryManager.Tool.Group.SelectGroup")); TargetList list = new TargetList(); dialog.insertBeforeButtons(list); @@ -242,6 +249,5 @@ public TargetList getParentWidget() { private boolean isSelected() { return getParentWidget().selected == this.index; } - } } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java new file mode 100644 index 000000000..fb3e87615 --- /dev/null +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java @@ -0,0 +1,78 @@ +package vswe.stevesfactory.ui.manager.tool.inspector; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.platform.GlStateManager; +import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; +import vswe.stevesfactory.library.gui.layout.FlowLayout; +import vswe.stevesfactory.library.gui.widget.AbstractContainer; +import vswe.stevesfactory.library.gui.widget.IWidget; +import vswe.stevesfactory.ui.manager.FactoryManagerGUI; +import vswe.stevesfactory.ui.manager.editor.FlowComponent; + +import javax.annotation.Nullable; +import java.util.List; + +import static org.lwjgl.opengl.GL11.*; + +public class Inspector extends AbstractContainer { + + @Nullable + public static Inspector getActiveInspector() { + IWidget tool = FactoryManagerGUI.get().getTopLevel().toolHolderPanel.getContainedWidget(); + if (tool instanceof Inspector) { + return (Inspector) tool; + } else { + return null; + } + } + + private final List children; + private final StatusPanel status; + private final PropertiesPanel props; + + public Inspector() { + super(0, 0, 120, 0); + + status = new StatusPanel(); // with fixed size + status.setParentWidget(this); + props = new PropertiesPanel(); + props.setParentWidget(this); + children = ImmutableList.of(status, props); + reflow(); + } + + public void openFlowComponent(FlowComponent target) { + status.openFlowComponent(target); + props.openFlowComponent(target); + } + + @Override + public void render(int mouseX, int mouseY, float particleTicks) { + RenderEventDispatcher.onPreRender(this, mouseX, mouseY); + + GlStateManager.disableTexture(); + GlStateManager.lineWidth(1F); + GlStateManager.color3f(64F / 255F, 64F / 255F, 64F / 255F); + int y = status.getAbsoluteYBottom() + 1; + glBegin(GL_LINES); + glVertex3f(status.getAbsoluteX(), y, 0F); + glVertex3f(status.getAbsoluteXRight(), y, 0F); + glEnd(); + GlStateManager.enableTexture(); + + super.render(mouseX, mouseY, particleTicks); + RenderEventDispatcher.onPostRender(this, mouseX, mouseY); + } + + @Override + public List getChildren() { + return children; + } + + @Override + public void reflow() { + // 3px gap for the divider line (1px) + FlowLayout.vertical(children, 0, 0, 3); + props.setHeight(this.getHeight() - status.getHeight() - 3); + } +} diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/PropertiesPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/PropertiesPanel.java new file mode 100644 index 000000000..8d4d1e39a --- /dev/null +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/PropertiesPanel.java @@ -0,0 +1,44 @@ +package vswe.stevesfactory.ui.manager.tool.inspector; + +import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; +import vswe.stevesfactory.library.gui.widget.AbstractContainer; +import vswe.stevesfactory.library.gui.widget.box.LinearList; +import vswe.stevesfactory.ui.manager.editor.FlowComponent; +import vswe.stevesfactory.ui.manager.editor.Menu; + +import java.util.ArrayList; +import java.util.List; + +public class PropertiesPanel extends AbstractContainer>> { + + private List>> child = new ArrayList<>(); + + public PropertiesPanel() { + super(0, 0, 120, 0); + } + + @Override + public void render(int mouseX, int mouseY, float particleTicks) { + RenderEventDispatcher.onPreRender(this, mouseX, mouseY); + super.render(mouseX, mouseY, particleTicks); + RenderEventDispatcher.onPostRender(this, mouseX, mouseY); + } + + @Override + public List>> getChildren() { + return child; + } + + @Override + public void reflow() { + } + + public void openFlowComponent(FlowComponent target) { + @SuppressWarnings({"rawtypes", "unchecked"}) LinearList> menusBox = (LinearList) target.getMenusBox(); + // Hacky way to maintain the list to hold one item exactly + child.clear(); + child.add(menusBox); + menusBox.setParentWidget(this); + menusBox.setDimensions(this.getDimensions()); + } +} diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java new file mode 100644 index 000000000..da2a81dd9 --- /dev/null +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java @@ -0,0 +1,59 @@ +package vswe.stevesfactory.ui.manager.tool.inspector; + +import net.minecraft.client.resources.I18n; +import vswe.stevesfactory.library.gui.RenderingHelper; +import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; +import vswe.stevesfactory.library.gui.widget.AbstractContainer; +import vswe.stevesfactory.library.gui.widget.IWidget; +import vswe.stevesfactory.ui.manager.editor.FlowComponent; +import vswe.stevesfactory.ui.manager.tool.group.GroupButton; +import vswe.stevesfactory.ui.manager.tool.group.GroupDataModel; +import vswe.stevesfactory.ui.manager.tool.group.Grouplist; +import vswe.stevesfactory.ui.manager.toolbox.ToolboxPanel; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class StatusPanel extends AbstractContainer { + + private FlowComponent opened = null; + private List children = new ArrayList<>(); + + public StatusPanel() { + super(0, 0, 120, 64); + } + + @Override + public void render(int mouseX, int mouseY, float particleTicks) { + RenderEventDispatcher.onPreRender(this, mouseX, mouseY); + + int x = getAbsoluteX(); + int y = getAbsoluteY(); + if (opened != null) { + int y1 = y + 2; + RenderingHelper.drawText(opened.getName(), x + 2, y1, 9, 0xff404040); + int y2 = y1 + 9 /* font height of name */ + 2 /* margin */; + ToolboxPanel.GROUP_LIST_ICON.draw(x + 2, y2, 8, 8); + RenderingHelper.drawText(GroupButton.formatGroupName(opened.getGroup()), x + 2 + 8 + 2, y2, 7, 0xff404040); + } else { + RenderingHelper.drawText(I18n.format("gui.sfm.FactoryManager.Tool.Inspector.NoTarget"), x + 2, y + 2, 9, 0xff404040); + } + + super.render(mouseX, mouseY, particleTicks); + RenderEventDispatcher.onPostRender(this, mouseX, mouseY); + } + + @Override + public Collection getChildren() { + return children; + } + + @Override + public void reflow() { + } + + public void openFlowComponent(FlowComponent target) { + this.opened = target; + } +} diff --git a/src/main/java/vswe/stevesfactory/ui/manager/toolbox/IconToolType.java b/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxEntry.java similarity index 89% rename from src/main/java/vswe/stevesfactory/ui/manager/toolbox/IconToolType.java rename to src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxEntry.java index 41f25ee24..4903e1ae0 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/toolbox/IconToolType.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxEntry.java @@ -12,7 +12,6 @@ import vswe.stevesfactory.library.gui.widget.IWidget; import vswe.stevesfactory.library.gui.widget.mixin.LeafWidgetMixin; import vswe.stevesfactory.ui.manager.FactoryManagerGUI; -import vswe.stevesfactory.ui.manager.tool.ToolPanel; import java.util.function.Supplier; @@ -20,7 +19,7 @@ import static vswe.stevesfactory.library.gui.RenderingHelper.rectVertices; import static vswe.stevesfactory.library.gui.RenderingHelper.textWidth; -public class IconToolType extends AbstractWidget implements IToolType, LeafWidgetMixin { +public class ToolboxEntry extends AbstractWidget implements IToolType, LeafWidgetMixin { public static final int NORMAL_BORDER_COLOR = 0xff8c8c8c; public static final int HOVERED_BORDER_COLOR = 0xff8c8c8c; @@ -36,8 +35,8 @@ public class IconToolType extends AbstractWidget implements I private Supplier toolWindowConstructor; private T cachedToolWindow; - public IconToolType(TextureWrapper tex, Supplier toolWindowConstructor) { - super(0, 0, tex.getPortionWidth() / 2, tex.getPortionHeight() / 2); + public ToolboxEntry(TextureWrapper tex, Supplier toolWindowConstructor) { + super(0, 0, Math.max(tex.getPortionWidth() / 2, 8), tex.getPortionHeight() / 2); this.tex = tex; this.toolWindowConstructor = toolWindowConstructor; } @@ -73,7 +72,7 @@ public void render(int mouseX, int mouseY, float particleTicks) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - FactoryManagerGUI.get().getTopLevel().toolPanel.setActivePanel(getToolWindow()); + FactoryManagerGUI.get().getTopLevel().toolHolderPanel.setActivePanel(getToolWindow()); return true; } @@ -89,7 +88,7 @@ public String getName() { return name; } - public IconToolType setName(String name) { + public ToolboxEntry setName(String name) { this.name = name; this.setHeight(getHeight() + LABEL_VERTICAL_GAP + textWidth(name, FONT_HEIGHT) + LABEL_VERTICAL_GAP); return this; diff --git a/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxPanel.java index cb52d99b2..6b24eaed3 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/toolbox/ToolboxPanel.java @@ -14,10 +14,13 @@ import vswe.stevesfactory.library.gui.widget.IWidget; import vswe.stevesfactory.ui.manager.DynamicWidthWidget; import vswe.stevesfactory.ui.manager.FactoryManagerGUI; -import vswe.stevesfactory.ui.manager.tool.ToolPanel; +import vswe.stevesfactory.ui.manager.tool.ToolHolderPanel; import vswe.stevesfactory.ui.manager.tool.group.Grouplist; +import vswe.stevesfactory.ui.manager.tool.inspector.Inspector; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LEFT; import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_RIGHT; @@ -25,8 +28,10 @@ public final class ToolboxPanel extends DynamicWidthWidget { public static final TextureWrapper GROUP_LIST_ICON = TextureWrapper.ofGUITexture("tool_icon/group.png", 16, 16, 0, 0, 16, 16); + public static final TextureWrapper INSPECTOR_ICON = TextureWrapper.ofGUITexture("tool_icon/inspector.png", 16, 16, 0, 0, 16, 16); - private final IconToolType groupList; + private final ToolboxEntry groupList; + private final ToolboxEntry inspector; private final AbstractIconButton close; private final List children = new ArrayList<>(); @@ -34,7 +39,8 @@ public ToolboxPanel() { super(WidthOccupierType.MIN_WIDTH); this.setWidth(8 + RenderingHelper.LEFT_BORDER); - addChildOnly(groupList = new IconToolType<>(GROUP_LIST_ICON, Grouplist::new).setName(I18n.format("gui.sfm.FactoryManager.Tool.Group.Name"))); + addChildOnly(groupList = new ToolboxEntry<>(GROUP_LIST_ICON, Grouplist::new).setName(I18n.format("gui.sfm.FactoryManager.Tool.Group.Name"))); + addChildOnly(inspector = new ToolboxEntry<>(INSPECTOR_ICON, Inspector::new).setName(I18n.format("gui.sfm.FactoryManager.Tool.Inspector.Name"))); addChildOnly(close = new AbstractIconButton(0, 0, 8, 8) { @Override public void render(int mouseX, int mouseY, float particleTicks) { @@ -46,7 +52,7 @@ public void render(int mouseX, int mouseY, float particleTicks) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - ToolPanel panel = FactoryManagerGUI.get().getPrimaryWindow().topLevel.toolPanel; + ToolHolderPanel panel = FactoryManagerGUI.get().getPrimaryWindow().topLevel.toolHolderPanel; panel.setActivePanel(null); return true; } @@ -128,7 +134,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { private void openActionMenu() { ContextMenu contextMenu = ContextMenu.atCursor(ImmutableList.of( - new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.CtxMenu.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) + new CallbackEntry(null, "gui.sfm.FactoryManager.Generic.ToggleFullscreen", b -> FactoryManagerGUI.get().getPrimaryWindow().toggleFullscreen()) )); WidgetScreen.getCurrent().addPopupWindow(contextMenu); } @@ -136,4 +142,8 @@ private void openActionMenu() { public Grouplist getGroupList() { return groupList.getToolWindow(); } + + public Inspector getInspector() { + return inspector.getToolWindow(); + } } diff --git a/src/main/resources/assets/sfm/lang/en_us.json b/src/main/resources/assets/sfm/lang/en_us.json index fdcf4fcce..c29a6913c 100644 --- a/src/main/resources/assets/sfm/lang/en_us.json +++ b/src/main/resources/assets/sfm/lang/en_us.json @@ -33,35 +33,39 @@ "gui.sfm.buckets": "Buckets", "gui.sfm.WrappingList.SearchStatus": "Found: %d", "gui.sfm.FactoryManager.Generic.Title": "Factory Manager", - "gui.sfm.FactoryManager.Generic.CtxMenu.ToggleFullscreen": "Toggle Fullscreen", + "gui.sfm.FactoryManager.Generic.ToggleFullscreen": "Toggle Fullscreen", "gui.sfm.FactoryManager.Selection.NoComponentGroupsPresent": "No members specified", "gui.sfm.FactoryManager.Editor.XOff": "X: ", "gui.sfm.FactoryManager.Editor.YOff": "Y: ", "gui.sfm.FactoryManager.Editor.EditOffset": "Enter a new offset: ", - "gui.sfm.FactoryManager.Editor.InvalidNumberFormat": "Invalid number format: %s!", - "gui.sfm.FactoryManager.Editor.CtxMenu.Delete": "Delete", - "gui.sfm.FactoryManager.Editor.CtxMenu.DeleteAll": "Delete all", - "gui.sfm.FactoryManager.Editor.Dialog.DeleteAll.ConfirmMsg": "Are you sure you want to delete all connected procedures?", - "gui.sfm.FactoryManager.Editor.CtxMenu.Cut": "Cut", - "gui.sfm.FactoryManager.Editor.CtxMenu.Copy": "Copy", - "gui.sfm.FactoryManager.Editor.CtxMenu.Paste": "Paste", - "gui.sfm.FactoryManager.Editor.CtxMenu.ChangeGroup": "Change group", - "gui.sfm.FactoryManager.Editor.Dialog.PasteProcedure.Fail": "Failed to paste procedure: invalid syntax. Please check your clipboard string again to make sure that it is from copying/cutting another procedure", - "gui.sfm.FactoryManager.Editor.CtxMenu.CleanupProcedures": "Cleanup", - "gui.sfm.FactoryManager.Editor.CtxMenu.CollapseAll": "Collapse All", - "gui.sfm.FactoryManager.Editor.CtxMenu.ExpandAll": "Expand All", - "gui.sfm.FactoryManager.Editor.CtxMenu.CycleProperty": "Cycle to next property", - "gui.sfm.FactoryManager.Editor.CtxMenu.CycleProperty.Named": "Change to %s", + "gui.sfm.FactoryManager.Editor.Delete": "Delete", + "gui.sfm.FactoryManager.Editor.DeleteAll": "Delete all", + "gui.sfm.FactoryManager.Editor.DeleteAll.ConfirmMsg": "Are you sure you want to delete all connected procedures?", + "gui.sfm.FactoryManager.Editor.Cut": "Cut", + "gui.sfm.FactoryManager.Editor.Copy": "Copy", + "gui.sfm.FactoryManager.Editor.Paste": "Paste", + "gui.sfm.FactoryManager.Editor.Paste.Fail": "Failed to paste procedure: invalid syntax. Please check your clipboard string again to make sure that it is from copying/cutting another procedure", + "gui.sfm.FactoryManager.Editor.ChangeGroup": "Change group", + "gui.sfm.FactoryManager.Editor.CleanupProcedures": "Cleanup", "gui.sfm.FactoryManager.Tool.CtxMenu.CloseToolPanel": "Close current tool panel", "gui.sfm.FactoryManager.Tool.Group.Name": "Groups", "gui.sfm.FactoryManager.Tool.Group.DefaultGroup": "(default)", - "gui.sfm.FactoryManager.Tool.Group.CtxMenu.Delete": "Delete", - "gui.sfm.FactoryManager.Tool.Group.CtxMenu.RenameGroup": "Rename", - "gui.sfm.FactoryManager.Tool.Group.CtxMenu.MoveContent": "Move contents", - "gui.sfm.FactoryManager.Tool.Group.Dialog.RenameGroup": "Enter a new group name: ", - "gui.sfm.FactoryManager.Tool.Group.Dialog.CreateGroup": "Create new group", - "gui.sfm.FactoryManager.Tool.Group.Dialog.CreateFailed": "Unable to create new group: a group with the name %s already exists.", - "gui.sfm.FactoryManager.Tool.Group.Dialog.SelectGroup": "Select a group from the following list:", + "gui.sfm.FactoryManager.Tool.Group.CreateGroup": "Enter a group name:", + "gui.sfm.FactoryManager.Tool.Group.Delete": "Delete", + "gui.sfm.FactoryManager.Tool.Group.RenameGroup": "Rename", + "gui.sfm.FactoryManager.Tool.Group.RenameGroup.Prompt": "Enter a new group name: ", + "gui.sfm.FactoryManager.Tool.Group.RenameGroup.Failed": "Unable to rename group: a group with the new name %s already exists.", + "gui.sfm.FactoryManager.Tool.Group.MoveContent": "Move contents", + "gui.sfm.FactoryManager.Tool.Group.MoveContent.Prompt": "Enter a group name: ", + "gui.sfm.FactoryManager.Tool.Group.MoveContent.Failed": "Unable to move contents: no group with the name %s exists.", + "gui.sfm.FactoryManager.Tool.Group.SelectGroup": "Select a group from the following list:", + "gui.sfm.FactoryManager.Tool.Inspector.Name": "Inspector", + "gui.sfm.FactoryManager.Tool.Inspector.NoTarget": "None selected", + "gui.sfm.FactoryManager.Tool.Inspector.Props.CollapseAll": "Collapse All", + "gui.sfm.FactoryManager.Tool.Inspector.Props.ExpandAll": "Expand All", + "gui.sfm.FactoryManager.Tool.Inspector.Props.CycleProperty": "Cycle to next property", + "gui.sfm.FactoryManager.Tool.Inspector.Props.CycleProperty.Named": "Change to %s", + "gui.sfm.FactoryManager.Toolbox.CloseToolPanel": "Close tool panel", "gui.sfm.ItemIntake.Title": "Item Intake", "gui.sfm.ItemIntake.Radius": "Working area radius", "gui.sfm.ItemIntake.RenderWorkingArea": "Renders working area", diff --git a/src/main/resources/assets/sfm/textures/gui/flow_components.png b/src/main/resources/assets/sfm/textures/gui/flow_components.png index 462c0b688e58ee56af372487d69b572269e9c9e9..8b59fd3d23af1ce77c7b48ce177683cb0322be05 100644 GIT binary patch literal 11136 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 Date: Fri, 17 Apr 2020 15:05:08 -0700 Subject: [PATCH 2/3] Rename button on inspection panel --- src/main/java/vswe/stevesfactory/Config.java | 8 - .../gui/widget/CallbackIconButton.java | 59 ++++++ .../ui/manager/editor/EditorPanel.java | 16 -- .../ui/manager/editor/FlowComponent.java | 185 +----------------- .../stevesfactory/ui/manager/editor/Menu.java | 3 +- .../ui/manager/editor/OffsetText.java | 2 +- .../manager/tool/inspector/StatusPanel.java | 98 +++++++++- src/main/resources/assets/sfm/lang/en_us.json | 2 +- 8 files changed, 158 insertions(+), 215 deletions(-) create mode 100644 src/main/java/vswe/stevesfactory/library/gui/widget/CallbackIconButton.java diff --git a/src/main/java/vswe/stevesfactory/Config.java b/src/main/java/vswe/stevesfactory/Config.java index 2dac3776c..fdab4fa6c 100644 --- a/src/main/java/vswe/stevesfactory/Config.java +++ b/src/main/java/vswe/stevesfactory/Config.java @@ -138,8 +138,6 @@ public static final class ClientCategory { // Factory manager GUI options public final BooleanValue useFixedSizeScreen; public final BooleanValue useBackgroundOnFullscreen; - public final IntValue defaultEditorMoveSpeed; - public final IntValue acceleratedEditorMoveSpeed; private ClientCategory(Builder builder) { builder.comment("General client config options").push("general"); @@ -165,12 +163,6 @@ private ClientCategory(Builder builder) { useBackgroundOnFullscreen = builder .comment("Enable to use vanilla background instead of a plain rectangle") .define("useBackgroundOnFullscreen", false); - defaultEditorMoveSpeed = builder - .comment("Determines how fast arrow keys moving is (for editor panel)") - .defineInRange("defaultEditorMoveSpeed", 2, 0, Integer.MAX_VALUE); - acceleratedEditorMoveSpeed = builder - .comment("Determines how fast arrow keys moving is, while Shift is pressed") - .defineInRange("acceleratedEditorMoveSpeed", 20, 0, Integer.MAX_VALUE); builder.pop(); } } diff --git a/src/main/java/vswe/stevesfactory/library/gui/widget/CallbackIconButton.java b/src/main/java/vswe/stevesfactory/library/gui/widget/CallbackIconButton.java new file mode 100644 index 000000000..fe094477d --- /dev/null +++ b/src/main/java/vswe/stevesfactory/library/gui/widget/CallbackIconButton.java @@ -0,0 +1,59 @@ +package vswe.stevesfactory.library.gui.widget; + +import com.google.common.base.Preconditions; +import it.unimi.dsi.fastutil.ints.Int2BooleanFunction; +import vswe.stevesfactory.library.gui.TextureWrapper; + +public class CallbackIconButton extends AbstractIconButton { + + public static final Int2BooleanFunction DUMMY = b -> false; + + private TextureWrapper textureNormal; + private TextureWrapper textureHovering; + public Int2BooleanFunction onClick = DUMMY; + + public CallbackIconButton(TextureWrapper textureNormal, TextureWrapper textureHovering) { + super(0, 0, 0, 0); + this.setTextures(textureNormal, textureHovering); + } + + @Override + public TextureWrapper getTextureNormal() { + return textureNormal; + } + + @Override + public TextureWrapper getTextureHovered() { + return textureHovering; + } + + public void setTextureNormal(TextureWrapper textureNormal) { + checkArguments(textureNormal, textureHovering); + this.textureNormal = textureNormal; + this.setDimensions(textureNormal.getPortionWidth(), textureNormal.getPortionHeight()); + } + + public void setTextureHovering(TextureWrapper textureHovering) { + checkArguments(textureNormal, textureHovering); + this.textureHovering = textureHovering; + this.setDimensions(textureHovering.getPortionWidth(), textureHovering.getPortionHeight()); + } + + public void setTextures(TextureWrapper textureNormal, TextureWrapper textureHovering) { + checkArguments(textureNormal, textureHovering); + this.textureNormal = textureNormal; + this.textureHovering = textureHovering; + // Either one is fine, since we checked that they are the same size + this.setDimensions(textureNormal.getPortionWidth(), textureNormal.getPortionHeight()); + } + + private static void checkArguments(TextureWrapper textureNormal, TextureWrapper textureHovering) { + Preconditions.checkArgument(textureNormal.getPortionWidth() == textureHovering.getPortionWidth()); + Preconditions.checkArgument(textureNormal.getPortionHeight() == textureHovering.getPortionHeight()); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return onClick.apply(button); + } +} diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java index b4395c6be..f69ce75b9 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/EditorPanel.java @@ -253,22 +253,6 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { return true; } } - - int offset = Screen.hasShiftDown() ? Config.CLIENT.acceleratedEditorMoveSpeed.get() : Config.CLIENT.defaultEditorMoveSpeed.get(); - switch (keyCode) { - case GLFW_KEY_UP: - yOffset.add(offset); - break; - case GLFW_KEY_DOWN: - yOffset.subtract(offset); - break; - case GLFW_KEY_LEFT: - xOffset.add(offset); - break; - case GLFW_KEY_RIGHT: - xOffset.subtract(offset); - break; - } return false; } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java index b1becfd5f..fbbaa2d6b 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java @@ -39,170 +39,6 @@ public class FlowComponent

extends AbstractContainer implements Comparable> { - public static class RenameButton extends AbstractIconButton { - - public static final TextureWrapper NORMAL = TextureWrapper.ofFlowComponent(0, 124, 9, 9); - public static final TextureWrapper HOVERING = NORMAL.toRight(1); - - public RenameButton(FlowComponent parent) { - super(-1, -1, 9, 9); - setParentWidget(parent); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isEnabled() && button == GLFW_MOUSE_BUTTON_LEFT) { - setEnabled(false); - FlowComponent parent = getParentWidget(); - parent.submitButton.setEnabled(true); - parent.cancelButton.setEnabled(true); - parent.nameBox.setEditable(true); - getWindow().setFocusedWidget(parent.nameBox); - return true; - } - return false; - } - - @Override - public TextureWrapper getTextureNormal() { - return NORMAL; - } - - @Override - public TextureWrapper getTextureHovered() { - return HOVERING; - } - - @Nonnull - @Override - public FlowComponent getParentWidget() { - return Objects.requireNonNull((FlowComponent) super.getParentWidget()); - } - - @Override - public BoxSizing getBoxSizing() { - return BoxSizing.PHANTOM; - } - } - - public static class SubmitButton extends AbstractIconButton { - - public static final TextureWrapper NORMAL = TextureWrapper.ofFlowComponent(0, 133, 7, 7); - public static final TextureWrapper HOVERING = NORMAL.toRight(1); - - public SubmitButton(FlowComponent parent) { - super(-1, -1, 7, 7); - setParentWidget(parent); - setEnabled(false); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isEnabled() && button == GLFW_MOUSE_BUTTON_LEFT) { - submit(); - return true; - } - return false; - } - - public void submit() { - setEnabled(false); - FlowComponent parent = getParentWidget(); - parent.cancelButton.setEnabled(false); - parent.renameButton.setEnabled(true); - parent.nameBox.scrollToFront(); - parent.nameBox.setEditable(false); - parent.getDataHandler().setName(parent.getName()); - getWindow().changeFocus(parent.nameBox, false); - } - - @Override - public TextureWrapper getTextureNormal() { - return NORMAL; - } - - @Override - public TextureWrapper getTextureHovered() { - return HOVERING; - } - - @Nonnull - @Override - public FlowComponent getParentWidget() { - return Objects.requireNonNull((FlowComponent) super.getParentWidget()); - } - - @Override - public BoxSizing getBoxSizing() { - return BoxSizing.PHANTOM; - } - } - - public static class CancelButton extends AbstractIconButton { - - public static final TextureWrapper NORMAL = TextureWrapper.ofFlowComponent(0, 140, 7, 7); - public static final TextureWrapper HOVERING = NORMAL.toRight(1); - - private String previousName; - - public CancelButton(FlowComponent parent, String previousName) { - super(-1, -1, 7, 7); - setParentWidget(parent); - setEnabled(false); - this.previousName = previousName; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (isEnabled() && button == GLFW_MOUSE_BUTTON_LEFT) { - cancel(); - return true; - } - return false; - } - - public void cancel() { - setEnabled(false); - FlowComponent parent = getParentWidget(); - parent.submitButton.setEnabled(false); - parent.renameButton.setEnabled(true); - parent.setName(previousName); - parent.nameBox.scrollToFront(); - parent.nameBox.setEditable(false); - getWindow().changeFocus(parent.nameBox, false); - previousName = ""; - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (enabled) { - this.previousName = getParentWidget().getName(); - } - } - - @Override - public TextureWrapper getTextureNormal() { - return NORMAL; - } - - @Override - public TextureWrapper getTextureHovered() { - return HOVERING; - } - - @Nonnull - @Override - public FlowComponent getParentWidget() { - return Objects.requireNonNull((FlowComponent) super.getParentWidget()); - } - - @Override - public BoxSizing getBoxSizing() { - return BoxSizing.PHANTOM; - } - } - public static

FlowComponent

of(P procedure) { return new FlowComponent<>(procedure, procedure.predecessors().length, procedure.successors().length); } @@ -210,9 +46,7 @@ public static

FlowComponent

of(P private P procedure; private final MinimumLinearList> menus; - private final RenameButton renameButton; - private final SubmitButton submitButton; - private final CancelButton cancelButton; + private final TextField nameBox; private final ConnectionNodes inputNodes; private final ConnectionNodes outputNodes; @@ -229,12 +63,6 @@ public static

FlowComponent

of(P public FlowComponent(P procedure, int amountInputs, int amountOutputs) { super(0, 0, 64, 20); String name = procedure.getName(); - this.renameButton = new RenameButton(this); - this.renameButton.setLocation(52, 6); - this.submitButton = new SubmitButton(this); - this.submitButton.setLocation(54, 3); - this.cancelButton = new CancelButton(this, name); - this.cancelButton.setLocation(54, 11); // The cursor looks a bit to short (and cute) with these numbers, might want change them? this.nameBox = new TextField(6, 8, 45, 10); this.nameBox.setBackgroundStyle(TextField.BackgroundStyle.NONE); @@ -246,23 +74,18 @@ public FlowComponent(P procedure, int amountInputs, int amountOutputs) { this.outputNodes = ConnectionNodes.outputNodes(amountOutputs); this.errorIndicator = ErrorIndicator.error(); this.menus = new MinimumLinearList<>(0, 0); - this.children = ImmutableList.of(renameButton, submitButton, cancelButton, nameBox, inputNodes, outputNodes, errorIndicator); + this.children = ImmutableList.of(nameBox, inputNodes, outputNodes, errorIndicator); this.setLinkedProcedure(procedure); errorIndicator.setLocation(2, 8); } - public boolean isEditing() { - return submitButton.isEnabled(); - } - public String getName() { return nameBox.getText(); } public void setName(String name) { this.nameBox.setText(name); - this.cancelButton.previousName = getName(); this.procedure.setName(name); } @@ -333,10 +156,6 @@ public void render(int mouseX, int mouseY, float particleTicks) { int y = getAbsoluteY(); RenderingHelper.drawBorderedBox(x, y, x + getWidth(), y + getHeight()); - // Renaming state (showing different buttons at different times) is handled inside the widgets' render method - renameButton.render(mouseX, mouseY, particleTicks); - submitButton.render(mouseX, mouseY, particleTicks); - cancelButton.render(mouseX, mouseY, particleTicks); nameBox.render(mouseX, mouseY, particleTicks); RenderSystem.enableAlphaTest(); inputNodes.render(mouseX, mouseY, particleTicks); diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java index ff54a2726..9c5017cf3 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/Menu.java @@ -99,7 +99,7 @@ public void render(int mouseX, int mouseY, float particleTicks) { private static final List> EMPTY_LIST = ImmutableList.of(); - public static final TextureWrapper HEADING_BOX = TextureWrapper.ofFlowComponent(66, 152, 120, 13); + public static final TextureWrapper HEADING_BOX = TextureWrapper.ofFlowComponent(0, 0, 120, 13); public static final int DEFAULT_CONTENT_HEIGHT = 65; private FlowComponent

flowComponent; @@ -254,6 +254,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { ImmutableList.Builder list = ImmutableList.builder() .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Inspector.Props.CollapseAll", b -> flowComponent.collapseAllMenus())) .add(new CallbackEntry(null, "gui.sfm.FactoryManager.Tool.Inspector.Props.ExpandAll", b -> flowComponent.expandAllMenus())); + addContextMenuEntries(list); for (Supplier entry : actionMenuEntries) { list.add(entry.get()); } diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java index 9ac4f554e..d45791cdd 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/OffsetText.java @@ -70,7 +70,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { field.setValue(value); Dialog prompt = Dialog.createPrompt( - "gui.sfm.FactoryManager.Editor.PopupMsg.EditOffset", + "gui.sfm.FactoryManager.Editor.EditOffset", () -> field, "gui.sfm.ok", "gui.sfm.cancel", (b, s) -> { diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java index da2a81dd9..66c7e8e15 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java @@ -2,13 +2,14 @@ import net.minecraft.client.resources.I18n; import vswe.stevesfactory.library.gui.RenderingHelper; +import vswe.stevesfactory.library.gui.TextureWrapper; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; import vswe.stevesfactory.library.gui.widget.AbstractContainer; +import vswe.stevesfactory.library.gui.widget.CallbackIconButton; import vswe.stevesfactory.library.gui.widget.IWidget; +import vswe.stevesfactory.library.gui.widget.TextField; import vswe.stevesfactory.ui.manager.editor.FlowComponent; import vswe.stevesfactory.ui.manager.tool.group.GroupButton; -import vswe.stevesfactory.ui.manager.tool.group.GroupDataModel; -import vswe.stevesfactory.ui.manager.tool.group.Grouplist; import vswe.stevesfactory.ui.manager.toolbox.ToolboxPanel; import java.util.ArrayList; @@ -17,11 +18,95 @@ public class StatusPanel extends AbstractContainer { + public static final TextureWrapper RENAME_NORMAL = TextureWrapper.ofFlowComponent(0, 124, 9, 9); + public static final TextureWrapper RENAME_HOVERING = RENAME_NORMAL.toRight(1); + public static final TextureWrapper SUBMIT_NORMAL = TextureWrapper.ofFlowComponent(0, 133, 7, 7); + public static final TextureWrapper SUBMIT_HOVERING = SUBMIT_NORMAL.toRight(1); + public static final TextureWrapper CANCEL_NORMAL = TextureWrapper.ofFlowComponent(0, 140, 7, 7); + public static final TextureWrapper CANCEL_HOVERING = CANCEL_NORMAL.toRight(1); + private FlowComponent opened = null; private List children = new ArrayList<>(); + private TextField nameBox; + private CallbackIconButton renameButton; + private CallbackIconButton submitButton; + private CallbackIconButton cancelButton; + + private String previousName; public StatusPanel() { super(0, 0, 120, 64); + + nameBox = new TextField(2, 6, 100, 16); + nameBox.setParentWidget(this); + nameBox.setBackgroundStyle(TextField.BackgroundStyle.NONE); + nameBox.setTextColor(0xff303030, 0xff303030); + nameBox.setEditable(false); + children.add(nameBox); + + int baseX = getXRight() - 10; + int baseY = 2; + renameButton = new CallbackIconButton(RENAME_NORMAL, RENAME_HOVERING); + renameButton.setParentWidget(this); + renameButton.setLocation(baseX, baseY + 6); + renameButton.setEnabled(false); + renameButton.onClick = b -> { + if (renameButton.isEnabled() && opened != null) { + setRenamingState(); + return true; + } + return false; + }; + children.add(renameButton); + submitButton = new CallbackIconButton(SUBMIT_NORMAL, SUBMIT_HOVERING); + submitButton.setParentWidget(this); + submitButton.setLocation(baseX + 2, baseY + 3); + submitButton.setEnabled(false); + submitButton.onClick = b -> { + if (submitButton.isEnabled() && opened != null) { + // Keep input name + opened.setName(nameBox.getText()); + setWaitingState(); + return true; + } + return false; + }; + children.add(submitButton); + cancelButton = new CallbackIconButton(CANCEL_NORMAL, CANCEL_HOVERING); + cancelButton.setParentWidget(this); + cancelButton.setLocation(baseX + 2, baseY + 11); + cancelButton.setEnabled(false); + cancelButton.onClick = b -> { + if (cancelButton.isEnabled() && opened != null) { + // Discard input name + nameBox.setText(previousName); + opened.setName(previousName); + setWaitingState(); + return true; + } + return false; + }; + children.add(cancelButton); + } + + private void setRenamingState() { + renameButton.setEnabled(false); + submitButton.setEnabled(true); + cancelButton.setEnabled(true); + nameBox.setEditable(true); + nameBox.scrollToFront(); + previousName = nameBox.getText(); + getWindow().setFocusedWidget(nameBox); + } + + private void setWaitingState() { + renameButton.setEnabled(true); + submitButton.setEnabled(false); + cancelButton.setEnabled(false); + nameBox.setEditable(false); + nameBox.scrollToFront(); + previousName = ""; + getWindow().changeFocus(nameBox, false); } @Override @@ -31,9 +116,7 @@ public void render(int mouseX, int mouseY, float particleTicks) { int x = getAbsoluteX(); int y = getAbsoluteY(); if (opened != null) { - int y1 = y + 2; - RenderingHelper.drawText(opened.getName(), x + 2, y1, 9, 0xff404040); - int y2 = y1 + 9 /* font height of name */ + 2 /* margin */; + int y2 = y + 2 + 16 /* height of name */ + 2 /* margin */; ToolboxPanel.GROUP_LIST_ICON.draw(x + 2, y2, 8, 8); RenderingHelper.drawText(GroupButton.formatGroupName(opened.getGroup()), x + 2 + 8 + 2, y2, 7, 0xff404040); } else { @@ -55,5 +138,10 @@ public void reflow() { public void openFlowComponent(FlowComponent target) { this.opened = target; + + setWaitingState(); + nameBox.setText(target.getName()); + // For transition from to something selected + renameButton.setEnabled(true); } } diff --git a/src/main/resources/assets/sfm/lang/en_us.json b/src/main/resources/assets/sfm/lang/en_us.json index c29a6913c..4aa0dd629 100644 --- a/src/main/resources/assets/sfm/lang/en_us.json +++ b/src/main/resources/assets/sfm/lang/en_us.json @@ -60,7 +60,7 @@ "gui.sfm.FactoryManager.Tool.Group.MoveContent.Failed": "Unable to move contents: no group with the name %s exists.", "gui.sfm.FactoryManager.Tool.Group.SelectGroup": "Select a group from the following list:", "gui.sfm.FactoryManager.Tool.Inspector.Name": "Inspector", - "gui.sfm.FactoryManager.Tool.Inspector.NoTarget": "None selected", + "gui.sfm.FactoryManager.Tool.Inspector.NoTarget": "", "gui.sfm.FactoryManager.Tool.Inspector.Props.CollapseAll": "Collapse All", "gui.sfm.FactoryManager.Tool.Inspector.Props.ExpandAll": "Expand All", "gui.sfm.FactoryManager.Tool.Inspector.Props.CycleProperty": "Cycle to next property", From 08dc86ee99c02e56ed373002eca2e47d2932d13e Mon Sep 17 00:00:00 2001 From: hnOsmium0001 <36975818+hnOsmium0001@users.noreply.github.com> Date: Sun, 19 Apr 2020 16:47:08 -0700 Subject: [PATCH 3/3] Fix corrupted textures --- .../library/gui/TextureWrapper.java | 7 ++++++- .../library/gui/widget/TextList.java | 1 - .../ui/manager/editor/FlowComponent.java | 9 +++------ .../ui/manager/tool/inspector/Inspector.java | 10 +++++----- .../manager/tool/inspector/StatusPanel.java | 1 + .../sfm/textures/gui/flow_components.png | Bin 11136 -> 10997 bytes 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/vswe/stevesfactory/library/gui/TextureWrapper.java b/src/main/java/vswe/stevesfactory/library/gui/TextureWrapper.java index 282e73a18..fa0cd9aaa 100644 --- a/src/main/java/vswe/stevesfactory/library/gui/TextureWrapper.java +++ b/src/main/java/vswe/stevesfactory/library/gui/TextureWrapper.java @@ -1,6 +1,7 @@ package vswe.stevesfactory.library.gui; import com.google.common.base.MoreObjects; +import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; @@ -9,6 +10,8 @@ import java.awt.*; +import static org.lwjgl.opengl.GL11.GL_QUADS; + /** * Wraps around a ResourceLocation, used to simplify drawing 2D textures. */ @@ -57,8 +60,10 @@ public void draw(int x, int y) { } public void draw(int x, int y, int width, int height) { + RenderSystem.enableAlphaTest(); + RenderSystem.color3f(1F, 1F, 1F); RenderingHelper.bindTexture(texture); - RenderingHelper.getRenderer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + RenderingHelper.getRenderer().begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX); vertices(x, y, width, height); Tessellator.getInstance().draw(); } diff --git a/src/main/java/vswe/stevesfactory/library/gui/widget/TextList.java b/src/main/java/vswe/stevesfactory/library/gui/widget/TextList.java index ac429aa77..10f64c13a 100644 --- a/src/main/java/vswe/stevesfactory/library/gui/widget/TextList.java +++ b/src/main/java/vswe/stevesfactory/library/gui/widget/TextList.java @@ -1,6 +1,5 @@ package vswe.stevesfactory.library.gui.widget; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Minecraft; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; diff --git a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java index fbbaa2d6b..7562f323d 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/editor/FlowComponent.java @@ -1,23 +1,20 @@ package vswe.stevesfactory.ui.manager.editor; import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.nbt.CompoundNBT; import vswe.stevesfactory.api.logic.Connection; import vswe.stevesfactory.api.logic.IClientDataStorage; import vswe.stevesfactory.api.logic.IProcedure; import vswe.stevesfactory.library.gui.RenderingHelper; -import vswe.stevesfactory.library.gui.TextureWrapper; import vswe.stevesfactory.library.gui.contextmenu.CallbackEntry; import vswe.stevesfactory.library.gui.contextmenu.ContextMenu; import vswe.stevesfactory.library.gui.debug.ITextReceiver; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; -import vswe.stevesfactory.library.gui.layout.properties.BoxSizing; import vswe.stevesfactory.library.gui.screen.WidgetScreen; import vswe.stevesfactory.library.gui.widget.AbstractContainer; -import vswe.stevesfactory.library.gui.widget.AbstractIconButton; import vswe.stevesfactory.library.gui.widget.IWidget; import vswe.stevesfactory.library.gui.widget.TextField; import vswe.stevesfactory.library.gui.widget.box.LinearList; @@ -64,7 +61,8 @@ public FlowComponent(P procedure, int amountInputs, int amountOutputs) { super(0, 0, 64, 20); String name = procedure.getName(); // The cursor looks a bit to short (and cute) with these numbers, might want change them? - this.nameBox = new TextField(6, 8, 45, 10); + this.nameBox = new TextField(6, 8, 0, 10); + this.nameBox.setWidth(this.getWidth() - nameBox.getX() - 2); this.nameBox.setBackgroundStyle(TextField.BackgroundStyle.NONE); this.nameBox.setText(name); this.nameBox.setTextColor(0xff303030, 0xff303030); @@ -157,7 +155,6 @@ public void render(int mouseX, int mouseY, float particleTicks) { RenderingHelper.drawBorderedBox(x, y, x + getWidth(), y + getHeight()); nameBox.render(mouseX, mouseY, particleTicks); - RenderSystem.enableAlphaTest(); inputNodes.render(mouseX, mouseY, particleTicks); outputNodes.render(mouseX, mouseY, particleTicks); errorIndicator.render(mouseX, mouseY, particleTicks); diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java index fb3e87615..b8b1034aa 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/Inspector.java @@ -1,7 +1,7 @@ package vswe.stevesfactory.ui.manager.tool.inspector; import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import vswe.stevesfactory.library.gui.debug.RenderEventDispatcher; import vswe.stevesfactory.library.gui.layout.FlowLayout; import vswe.stevesfactory.library.gui.widget.AbstractContainer; @@ -50,15 +50,15 @@ public void openFlowComponent(FlowComponent target) { public void render(int mouseX, int mouseY, float particleTicks) { RenderEventDispatcher.onPreRender(this, mouseX, mouseY); - GlStateManager.disableTexture(); - GlStateManager.lineWidth(1F); - GlStateManager.color3f(64F / 255F, 64F / 255F, 64F / 255F); + RenderSystem.disableTexture(); + RenderSystem.lineWidth(1F); + RenderSystem.color3f(64F / 255F, 64F / 255F, 64F / 255F); int y = status.getAbsoluteYBottom() + 1; glBegin(GL_LINES); glVertex3f(status.getAbsoluteX(), y, 0F); glVertex3f(status.getAbsoluteXRight(), y, 0F); glEnd(); - GlStateManager.enableTexture(); + RenderSystem.enableTexture(); super.render(mouseX, mouseY, particleTicks); RenderEventDispatcher.onPostRender(this, mouseX, mouseY); diff --git a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java index 66c7e8e15..345035f1d 100644 --- a/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java +++ b/src/main/java/vswe/stevesfactory/ui/manager/tool/inspector/StatusPanel.java @@ -1,5 +1,6 @@ package vswe.stevesfactory.ui.manager.tool.inspector; +import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.resources.I18n; import vswe.stevesfactory.library.gui.RenderingHelper; import vswe.stevesfactory.library.gui.TextureWrapper; diff --git a/src/main/resources/assets/sfm/textures/gui/flow_components.png b/src/main/resources/assets/sfm/textures/gui/flow_components.png index 8b59fd3d23af1ce77c7b48ce177683cb0322be05..3e738ac3fb81f94592c28cae0cc5d14c84e6b49f 100644 GIT binary patch delta 10646 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 delta 10786 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 IFWZLyKgv8%NdN!<