package erogenousbeef.bigreactors.client.gui; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiTextField; import net.minecraft.inventory.Container; import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Keyboard; import erogenousbeef.bigreactors.common.BigReactors; import erogenousbeef.bigreactors.common.multiblock.block.BlockReactorPart; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort.CircuitType; import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedstonePort; import erogenousbeef.bigreactors.gui.controls.BeefGuiLabel; import erogenousbeef.bigreactors.gui.controls.GuiSelectableButton; import erogenousbeef.bigreactors.net.CommonPacketHandler; import erogenousbeef.bigreactors.net.message.ReactorRedstonePortChangeMessage; public class GuiReactorRedstonePort extends BeefGuiBase { private ResourceLocation _guiBackground; private TileEntityReactorRedstonePort port; BeefGuiLabel titleString; BeefGuiLabel settingString; private GuiButton commitBtn; private GuiButton resetBtn; // Subsetting display private BeefGuiLabel subSettingLabel; private GuiButton subInputButton; private GuiButton subInputButton2; private BeefGuiLabel subInputRodSettingLabel; private GuiTextField subInputRodSetting; // Also used as the pulse activation setting private BeefGuiLabel subInputRodSettingPctLabel; private BeefGuiLabel subInputRodSettingOffLabel; private GuiTextField subInputRodSettingOff; private BeefGuiLabel subInputRodSettingOffPctLabel; BeefGuiLabel subOutputValueLabel; private GuiTextField subOutputValue; // End Subsetting display private Map<CircuitType, GuiSelectableButton> btnMap; private int outputLevel; private boolean greaterThan; private boolean activeOnPulse; private boolean retract; private static final int MINIMUM_SETTING_SELECTOR_ID = 10; public GuiReactorRedstonePort(Container container, TileEntityReactorRedstonePort tileentity) { super(container); _guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedstonePort.png"); port = tileentity; ySize = 204; btnMap = new HashMap<CircuitType, GuiSelectableButton>(); outputLevel = tileentity.getOutputLevel(); greaterThan = tileentity.getGreaterThan(); activeOnPulse = tileentity.isInputActiveOnPulse(); if(outputLevel < 0) { retract = true; outputLevel = Math.abs(outputLevel); } else { retract = false; } } @Override public ResourceLocation getGuiBackground() { return _guiBackground; } private void registerCircuitButton(CircuitType ct, GuiSelectableButton btn) { this.btnMap.put(ct, btn); registerControl(btn); } @Override public void initGui() { super.initGui(); int leftX = guiLeft + 6; int topY = guiTop + 6; titleString = new BeefGuiLabel(this, "Reactor Redstone Port", leftX+2, topY); topY += titleString.getHeight() + 4; settingString = new BeefGuiLabel(this, "Pick a setting", leftX, topY); topY += settingString.getHeight() + 4; // Setting picker BlockReactorPart reactorPartBlock = (BlockReactorPart)BigReactors.blockReactorPart; int buttonOrdinal = MINIMUM_SETTING_SELECTOR_ID; leftX = guiLeft + 16; CircuitType currentCircuitType = port.getCircuitType(); for(CircuitType ct : CircuitType.values()) { if(ct == CircuitType.DISABLED) { continue; } GuiSelectableButton newBtn = new GuiSelectableButton(buttonOrdinal++, leftX, topY, reactorPartBlock.getRedNetConfigIcon(ct), 0xFF00FF00, this); newBtn.displayString = GuiReactorRedNetPort.grabbableTooltips[ct.ordinal()-1]; if(ct == currentCircuitType) { newBtn.setSelected(true); } leftX += 28; if(leftX > guiLeft + 130) { topY += 28; leftX = guiLeft + 16; } registerCircuitButton(ct, newBtn); } topY += 32; leftX = guiLeft + 6; // Subsetting display subSettingLabel = new BeefGuiLabel(this, "Settings", leftX, topY); topY += subSettingLabel.getHeight() + 4; subInputButton = new GuiButton(2, leftX, topY, 100, 20, "Activate on Pulse"); subInputButton2 = new GuiButton(3, leftX + xSize - 46, topY, 36, 20, "Mode"); topY += 24; subInputRodSettingLabel = new BeefGuiLabel(this, "While On", leftX, topY); subInputRodSettingOffLabel = new BeefGuiLabel(this, "While Off", leftX + xSize/2, topY); subOutputValue = new GuiTextField(this.fontRendererObj, leftX, topY, 60, 12); subOutputValue.setCanLoseFocus(true); subOutputValue.setMaxStringLength(7); subOutputValue.setText("0"); subOutputValue.setEnabled(true); subOutputValueLabel = new BeefGuiLabel(this, "C", leftX + 62, topY + 2); topY += subInputRodSettingLabel.getHeight() + 2; subInputRodSetting = new GuiTextField(this.fontRendererObj, leftX, topY, 32, 12); subInputRodSetting.setCanLoseFocus(true); subInputRodSetting.setMaxStringLength(3); subInputRodSetting.setText("0"); subInputRodSetting.setEnabled(true); subInputRodSettingPctLabel = new BeefGuiLabel(this, "%", leftX + 34, topY + 2); subInputRodSettingOff = new GuiTextField(this.fontRendererObj, leftX + xSize/2, topY, 32, 12); subInputRodSettingOff.setCanLoseFocus(true); subInputRodSettingOff.setMaxStringLength(3); subInputRodSettingOff.setText("0"); subInputRodSettingOff.setEnabled(true); subInputRodSettingOffPctLabel = new BeefGuiLabel(this, "%", leftX + xSize/2 + 34, topY + 2); topY += 24; // Bottom buttons commitBtn = new GuiButton(0, guiLeft + xSize - 60, guiTop + ySize - 24, 56, 20, "Commit"); commitBtn.enabled = false; resetBtn = new GuiButton(1, guiLeft + 4, guiTop + ySize - 24, 56, 20, "Reset"); registerControl(titleString); registerControl(settingString); registerControl(subSettingLabel); registerControl(subInputButton); registerControl(subInputButton2); registerControl(subInputRodSettingLabel); registerControl(subInputRodSettingOffLabel); registerControl(subInputRodSetting); registerControl(subInputRodSettingOff); registerControl(subInputRodSettingPctLabel); registerControl(subInputRodSettingOffPctLabel); registerControl(subOutputValue); registerControl(subOutputValueLabel); registerControl(commitBtn); registerControl(resetBtn); if(currentCircuitType == CircuitType.inputSetControlRod) { subInputRodSetting.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOn(this.outputLevel))); subInputRodSettingOff.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOff(this.outputLevel))); } else if(TileEntityReactorRedNetPort.isOutput(currentCircuitType)) { subOutputValue.setText(Integer.toString(this.outputLevel)); } updateSubSettings(currentCircuitType); if(TileEntityReactorRedNetPort.isInput(currentCircuitType)) { validateInputValues(); } else { validateOutputValues(); } } @Override public void updateScreen() { super.updateScreen(); CircuitType selectedSetting = getUserSelectedCircuitType(); updateSubSettings(selectedSetting); if(selectedSetting == port.getCircuitType()) { int actualOutputLevel = this.outputLevel; if(selectedSetting == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; } if(this.activeOnPulse != port.isInputActiveOnPulse() || this.greaterThan != port.getGreaterThan() || actualOutputLevel != port.getOutputLevel()) { commitBtn.enabled = true; } else { commitBtn.enabled = false; } } else { commitBtn.enabled = true; } } private void updateSubSettings(CircuitType selectedSetting) { this.subSettingLabel.setLabelText(getLabelFromSelectedSubSetting(selectedSetting)); updateSubSettingInputButton(selectedSetting); updateSubSettingTextFields(selectedSetting); } private String getLabelFromSelectedSubSetting(CircuitType selectedSetting) { switch(selectedSetting) { case inputActive: return "Input - Enable/Disable"; case inputEjectWaste: return "Input - Eject Waste"; case inputSetControlRod: return "Input - Control Rod Insertion"; case outputFuelAmount: return "Output - Fuel Amount"; case outputWasteAmount: return "Output - Waste Amount"; case outputFuelMix: return "Output - Fuel Enrichment %"; case outputFuelTemperature: return "Output - Fuel Temp (C)"; case outputCasingTemperature: return "Output - Casing Temp (C)"; case outputEnergyAmount: return "Output - Energy Amount (%)"; default: return ""; } } private void updateSubSettingInputButton(CircuitType selectedSetting) { subInputButton.visible = true; subInputButton2.visible = false; switch(selectedSetting) { case inputActive: subInputButton.enabled = true; if(this.activeOnPulse) { subInputButton.displayString = "Toggle on Pulse"; } else { subInputButton.displayString = "Set from Signal"; } break; case inputSetControlRod: subInputButton.enabled = true; if(this.activeOnPulse) { subInputButton2.visible = true; if(this.greaterThan) { if(this.retract) { subInputButton.displayString = "Retract on Pulse"; } else { subInputButton.displayString = "Insert on Pulse"; } } else { subInputButton.displayString = "Set on Pulse"; } } else { subInputButton.displayString = "Set from Signal"; } break; case inputEjectWaste: subInputButton.enabled = false; subInputButton.displayString = "Eject on Pulse"; break; case outputFuelTemperature: case outputCasingTemperature: case outputFuelMix: case outputFuelAmount: case outputWasteAmount: case outputEnergyAmount: subInputButton.enabled = true; if(this.greaterThan) { subInputButton.displayString = "Active While Above"; } else { subInputButton.displayString = "Active While Below"; } break; default: subInputButton.visible = false; } } private void updateSubSettingTextFields(CircuitType selectedSetting) { subOutputValueLabel.setLabelText(""); subInputRodSettingLabel.setLabelText(""); subInputRodSettingPctLabel.setLabelText(""); subInputRodSettingOffLabel.setLabelText(""); subInputRodSettingOffPctLabel.setLabelText(""); subOutputValueLabel.setLabelTooltip(""); subInputRodSetting.setVisible(false); subInputRodSettingOff.setVisible(false); subOutputValue.setVisible(false); switch(selectedSetting) { case outputFuelTemperature: case outputCasingTemperature: subOutputValueLabel.setLabelText("C"); subOutputValueLabel.setLabelTooltip("Degrees centigrade"); subOutputValue.setVisible(true); break; case outputFuelMix: subOutputValueLabel.setLabelText("%"); subOutputValueLabel.setLabelTooltip("% of total contents, 0% if empty"); subOutputValue.setVisible(true); break; case outputEnergyAmount: subOutputValueLabel.setLabelText("%"); subOutputValueLabel.setLabelTooltip("% of energy buffer filled, 0% if empty"); subOutputValue.setVisible(true); break; case outputFuelAmount: subOutputValueLabel.setLabelText("mB"); subOutputValueLabel.setLabelTooltip("Milli-buckets"); subOutputValue.setVisible(true); break; case outputWasteAmount: subOutputValueLabel.setLabelText("mB"); subOutputValueLabel.setLabelTooltip("Milli-buckets"); subOutputValue.setVisible(true); break; case inputSetControlRod: if(this.activeOnPulse) { if(this.greaterThan) { if(this.retract) { subInputRodSettingLabel.setLabelText("Retract by"); } else { subInputRodSettingLabel.setLabelText("Insert by"); } } else { subInputRodSettingLabel.setLabelText("Set to"); } } else { subInputRodSettingLabel.setLabelText("While On"); subInputRodSettingOffLabel.setLabelText("While Off"); subInputRodSettingOffPctLabel.setLabelText("%"); subInputRodSettingOff.setVisible(true); } subInputRodSetting.setVisible(true); subInputRodSettingPctLabel.setLabelText("%"); break; default: break; } } @Override protected void actionPerformed(GuiButton clickedButton) { if(clickedButton.id == 0) { CircuitType newCircuitType = getUserSelectedCircuitType(); int actualOutputLevel = this.outputLevel; if(newCircuitType == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; } CommonPacketHandler.INSTANCE.sendToServer(new ReactorRedstonePortChangeMessage(port, newCircuitType.ordinal(), actualOutputLevel, this.greaterThan, this.activeOnPulse)); } else if(clickedButton.id == 1) { for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) { pair.getValue().setSelected(pair.getKey() == port.getCircuitType()); } setSubSettingsToDefaults(port.getCircuitType()); } else if(clickedButton.id == 2) { CircuitType selectedCircuitType = this.getUserSelectedCircuitType(); if(TileEntityReactorRedNetPort.isInput(selectedCircuitType)) this.activeOnPulse = !this.activeOnPulse; else this.greaterThan = !this.greaterThan; } else if(clickedButton.id == 3) { if(this.greaterThan && !this.retract) { // Insert -> Retract this.greaterThan = true; this.retract = true; } else if(this.greaterThan && this.retract) { // Retract -> Set this.greaterThan = false; this.retract = false; } else { // Set -> Insert this.greaterThan = true; this.retract = false; // Doesn't actually matter, but hey, keeping it tidy. } } else if(clickedButton.id >= MINIMUM_SETTING_SELECTOR_ID && clickedButton.id < MINIMUM_SETTING_SELECTOR_ID + btnMap.size()) { CircuitType ct = CircuitType.DISABLED; for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) { GuiSelectableButton btn = pair.getValue(); btn.setSelected(btn.id == clickedButton.id); if(btn.isSelected()) { ct = pair.getKey(); } } setSubSettingsToDefaults(ct); } } private void setSubSettingsToDefaults(CircuitType selectedType) { if(port.getCircuitType() == selectedType) { // RESTORE ALL THE DEFAULTS this.outputLevel = port.getOutputLevel(); this.greaterThan = port.getGreaterThan(); this.activeOnPulse = port.isInputActiveOnPulse(); if(this.outputLevel < 0) { this.retract = true; this.outputLevel = Math.abs(this.outputLevel); } else { this.retract = false; } } else { this.greaterThan = true; this.activeOnPulse = false; this.outputLevel = 0; // We do this so the state of the fields is accurate for the following two methods updateSubSettingTextFields(selectedType); // This should reset outputLevel from stored values if(TileEntityReactorRedNetPort.isInput(selectedType)) { this.validateInputValues(); } else { this.validateOutputValues(); } } this.subInputRodSetting.setFocused(false); this.subInputRodSettingOff.setFocused(false); this.subOutputValue.setFocused(false); } // Allow 0-9 (regular or numpad), backspace, delete, left/right arrows. private boolean isKeyValidForValueInput(int keyCode) { if(keyCode >= Keyboard.KEY_1 && keyCode <= Keyboard.KEY_0) { return true; } switch(keyCode) { case Keyboard.KEY_NUMPAD0: case Keyboard.KEY_NUMPAD1: case Keyboard.KEY_NUMPAD2: case Keyboard.KEY_NUMPAD3: case Keyboard.KEY_NUMPAD4: case Keyboard.KEY_NUMPAD5: case Keyboard.KEY_NUMPAD6: case Keyboard.KEY_NUMPAD7: case Keyboard.KEY_NUMPAD8: case Keyboard.KEY_NUMPAD9: case Keyboard.KEY_DELETE: case Keyboard.KEY_BACK: case Keyboard.KEY_LEFT: case Keyboard.KEY_RIGHT: return true; default: return false; } } @Override protected void keyTyped(char inputChar, int keyCode) { boolean isAnyTextboxFocused = this.subInputRodSetting.isFocused() || this.subInputRodSettingOff.isFocused() || this.subOutputValue.isFocused(); if (keyCode == Keyboard.KEY_ESCAPE || (!isAnyTextboxFocused && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) { this.mc.thePlayer.closeScreen(); } // Allow arrow keys, 0-9, and delete if(isKeyValidForValueInput(keyCode)) { if(this.subInputRodSetting.isFocused()) { this.subInputRodSetting.textboxKeyTyped(inputChar, keyCode); validateInputValues(); } if(this.subInputRodSettingOff.isFocused()) { this.subInputRodSettingOff.textboxKeyTyped(inputChar, keyCode); validateInputValues(); } if(this.subOutputValue.isFocused()) { this.subOutputValue.textboxKeyTyped(inputChar, keyCode); validateOutputValues(); } } if(keyCode == Keyboard.KEY_TAB) { /// ffffffuuuuuuuck tabbing if(this.subOutputValue.isFocused()) { this.subOutputValue.setFocused(false); } else if(this.subOutputValue.getVisible()) { this.subOutputValue.setFocused(true); } if(this.subInputRodSettingOff.getVisible()) { if(this.subInputRodSetting.isFocused()) { this.subInputRodSetting.setFocused(false); this.subInputRodSettingOff.setFocused(true); } else if(this.subInputRodSettingOff.isFocused()) { this.subInputRodSettingOff.setFocused(false); } else { this.subInputRodSetting.setFocused(true); } } else if(this.subInputRodSetting.getVisible()) { if(this.subInputRodSetting.isFocused()) { this.subInputRodSetting.setFocused(false); } else { this.subInputRodSetting.setFocused(true); } } // Else, nothing is visible, nothing is focused, screw you. } if(keyCode == Keyboard.KEY_RETURN && isAnyTextboxFocused) { this.subInputRodSetting.setFocused(false); this.subInputRodSettingOff.setFocused(false); this.subOutputValue.setFocused(false); } } private void validateInputValues() { outputLevel = 0; String in1 = this.subInputRodSetting.getText(); int val1; if(in1.isEmpty()) { val1 = 0; } else { val1 = Integer.parseInt(in1); if(val1 < 0) { val1 = 0; } else if(val1 > 100) { val1 = 100; } } this.subInputRodSetting.setText(Integer.toString(val1)); if(this.subInputRodSettingOff.getVisible()) { int val2; String in2 = this.subInputRodSettingOff.getText(); if(in2.isEmpty()) { val2 = 0; } else { val2 = Integer.parseInt(in2); if(val2 < 0) { val2 = 0; } else if(val2 > 100) { val2 = 100; } } // pack into high-order bits this.outputLevel = (val2 << 8) & 0xFF00; this.subInputRodSettingOff.setText(Integer.toString(val2)); } else { // Preserve high-order bits this.outputLevel = this.outputLevel & 0xFF00; } // Pack in low-order bits this.outputLevel |= val1 & 0xFF; } private void validateOutputValues() { CircuitType selectedType = getUserSelectedCircuitType(); int maxVal = Integer.MAX_VALUE; if(selectedType == CircuitType.outputFuelMix || selectedType == CircuitType.outputEnergyAmount) { // Percentile maxVal = 100; } String in1 = this.subOutputValue.getText(); int val1; if(in1.isEmpty()) { val1 = 0; } else { val1 = Integer.parseInt(in1); if(val1 < 0) { val1 = 0; } else if(val1 > maxVal) { val1 = maxVal; } } this.subOutputValue.setText(Integer.toString(val1)); this.outputLevel = val1; } private CircuitType getUserSelectedCircuitType() { for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) { if(pair.getValue().isSelected()) { return pair.getKey(); } } return CircuitType.DISABLED; } }