/**
* DRO style display panel with current controller state and most recent gcode
* comment.
*/
/*
Copywrite 2016-2017 Will Winder
This file is part of Universal Gcode Sender (UGS).
UGS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UGS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UGS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.willwinder.universalgcodesender.uielements.panels;
import com.willwinder.universalgcodesender.i18n.Localization;
import com.willwinder.universalgcodesender.listeners.ControllerListener;
import com.willwinder.universalgcodesender.listeners.ControllerStatus;
import com.willwinder.universalgcodesender.listeners.ControllerStatus.EnabledPins;
import com.willwinder.universalgcodesender.listeners.UGSEventListener;
import com.willwinder.universalgcodesender.model.BackendAPI;
import com.willwinder.universalgcodesender.model.Position;
import com.willwinder.universalgcodesender.model.UGSEvent;
import static com.willwinder.universalgcodesender.model.UGSEvent.ControlState.COMM_DISCONNECTED;
import com.willwinder.universalgcodesender.model.UnitUtils.Units;
import com.willwinder.universalgcodesender.types.GcodeCommand;
import static com.willwinder.universalgcodesender.utils.GUIHelpers.displayErrorDialog;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import java.io.InputStream;
import java.text.DecimalFormat;
public class MachineStatusPanel extends JPanel implements UGSEventListener, ControllerListener {
private final JLabel activeStateLabel = new JLabel("Active State:");
private final JLabel activeStateValueLabel = new JLabel(" ");
private final JLabel machinePositionLabel = new JLabel(Localization.getString("mainWindow.swing.machinePosition"));
private final JLabel machinePositionXLabel = new JLabel("X:");
private final JLabel machinePositionXValue = new JLabel("0.00");
private final JLabel machinePositionYLabel = new JLabel("Y:");
private final JLabel machinePositionYValue = new JLabel("0.00");
private final JLabel machinePositionZLabel = new JLabel("Z:");
private final JLabel machinePositionZValue = new JLabel("0.00");
private final JLabel workPositionLabel = new JLabel(Localization.getString("mainWindow.swing.workPositionLabel"));
private final JLabel workPositionXLabel = new JLabel("X:");
private final JLabel workPositionXValue = new JLabel("0.00");
private final JLabel workPositionYLabel = new JLabel("Y:");
private final JLabel workPositionYValue = new JLabel("0.00");
private final JLabel workPositionZLabel = new JLabel("Z:");
private final JLabel workPositionZValue = new JLabel("0.00");
private final JLabel latestCommentLabel = new JLabel(Localization.getString("mainWindow.swing.latestCommentLabel"));
private final JLabel latestCommentValueLabel = new JLabel(" ");
// Enabled pin reporting
private final JPanel pinStatusPanel = new JPanel();
private final JCheckBox pinX = new JCheckBox(Localization.getString("machineStatus.pin.x"));
private final JCheckBox pinY = new JCheckBox(Localization.getString("machineStatus.pin.y"));
private final JCheckBox pinZ = new JCheckBox(Localization.getString("machineStatus.pin.z"));
private final JCheckBox pinProbe = new JCheckBox(Localization.getString("machineStatus.pin.probe"));
private final JCheckBox pinDoor = new JCheckBox(Localization.getString("machineStatus.pin.door"));
private final JCheckBox pinHold = new JCheckBox(Localization.getString("machineStatus.pin.hold"));
private final JCheckBox pinSoftReset = new JCheckBox(Localization.getString("machineStatus.pin.softReset"));
private final JCheckBox pinCycleStart = new JCheckBox(Localization.getString("machineStatus.pin.cycleStart"));
// Reset individual coordinate buttons.
private final JButton resetXButton = new JButton(Localization.getString("mainWindow.swing.reset"));
private final JButton resetYButton = new JButton(Localization.getString("mainWindow.swing.reset"));
private final JButton resetZButton = new JButton(Localization.getString("mainWindow.swing.reset"));
private final BackendAPI backend;
public Units units;
public DecimalFormat decimalFormatter;
// Don't add the pin status panel until we get a pin status update.
private boolean addedPinStatusPanel = false;
public MachineStatusPanel(BackendAPI backend) {
activeStateLabel.setOpaque(true);
activeStateValueLabel.setOpaque(true);
this.backend = backend;
if (this.backend != null) {
this.backend.addUGSEventListener(this);
this.backend.addControllerListener(this);
}
applyFont();
initComponents();
if (this.backend.getSettings().getDefaultUnits().equals(Units.MM.abbreviation)) {
setUnits(Units.MM);
} else {
setUnits(Units.INCH);
}
updateControls();
}
private void applyFont() {
String fontPath="/resources/";
String fontName="LED.ttf";
InputStream is = getClass().getResourceAsStream(fontPath+fontName);
Font font;
Font big, small;
try {
font = Font.createFont(Font.TRUETYPE_FONT, is);
big = font.deriveFont(Font.PLAIN,30);
small = font.deriveFont(Font.PLAIN,18);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(fontName + " not loaded. Using serif font.");
big = new Font("serif", Font.PLAIN, 24);
small = new Font("serif", Font.PLAIN, 17);
}
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(big);
ge.registerFont(small);
this.machinePositionXValue.setFont(small);
this.machinePositionXValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
this.machinePositionYValue.setFont(small);
this.machinePositionYValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
this.machinePositionZValue.setFont(small);
this.machinePositionZValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
this.workPositionXValue.setFont(big);
this.workPositionXValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
this.workPositionYValue.setFont(big);
this.workPositionYValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
this.workPositionZValue.setFont(big);
this.workPositionZValue.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
}
private void initComponents() {
// Hookup the reset buttons.
resetXButton.addActionListener(ae -> resetCoordinateButton('X'));
resetYButton.addActionListener(ae -> resetCoordinateButton('Y'));
resetZButton.addActionListener(ae -> resetCoordinateButton('Z'));
String debug = "";
//String debug = "debug, ";
// MigLayout... 3rd party layout library.
MigLayout layout = new MigLayout(debug + "fill, wrap 2");
setLayout(layout);
add(activeStateLabel, "al right");
add(activeStateValueLabel);
add(latestCommentLabel, "al right");
add(latestCommentValueLabel);
// Subpanels for work/machine read outs.
JPanel workPanel = new JPanel();
workPanel.setBackground(Color.LIGHT_GRAY);
workPanel.setLayout(new MigLayout(debug + "fillx, wrap 3, inset 8", "[left][right][grow, right]"));
//workPanel.add(workPositionLabel, "span 2, wrap");
workPanel.add(resetXButton);
workPanel.add(workPositionXLabel, "al right");
workPanel.add(workPositionXValue, "growx, bottom");
workPanel.add(machinePositionXValue, "span 3, al right, wrap");
workPanel.add(resetYButton);
workPanel.add(workPositionYLabel, "al right");
workPanel.add(workPositionYValue, "growx, bottom");
workPanel.add(machinePositionYValue, "span 3, al right, wrap");
workPanel.add(resetZButton);
workPanel.add(workPositionZLabel, "al right");
workPanel.add(workPositionZValue, "growx, bottom");
workPanel.add(machinePositionZValue, "span 3, al right, wrap");
add(workPanel,"growx, span 2");
// Enabled pin reporting.
pinStatusPanel.setLayout(new MigLayout("flowy, wrap 3"));
pinStatusPanel.add(pinX);
pinX.setEnabled(false);
pinStatusPanel.add(pinY);
pinY.setEnabled(false);
pinStatusPanel.add(pinZ);
pinZ.setEnabled(false);
pinStatusPanel.add(pinProbe);
pinProbe.setEnabled(false);
pinStatusPanel.add(pinDoor);
pinDoor.setEnabled(false);
pinStatusPanel.add(pinHold);
pinHold.setEnabled(false);
pinStatusPanel.add(pinSoftReset);
pinSoftReset.setEnabled(false);
pinStatusPanel.add(pinCycleStart);
pinCycleStart.setEnabled(false);
}
private void setUnits(Units u) {
if (u == null || units == u) return;
units = u;
switch(u) {
case MM:
this.decimalFormatter = new DecimalFormat("0.00");
break;
case INCH:
this.decimalFormatter = new DecimalFormat("0.000");
break;
default:
units = Units.MM;
this.decimalFormatter = new DecimalFormat("0.00");
break;
}
}
@Override
public void doLayout() {
super.doLayout();
}
@Override
public void UGSEvent(UGSEvent evt) {
if (evt.isStateChangeEvent()) {
updateControls();
}
}
private void updateResetButtons(boolean enabled) {
this.resetXButton.setEnabled(enabled);
this.resetYButton.setEnabled(enabled);
this.resetZButton.setEnabled(enabled);
}
private void updateControls() {
updateResetButtons(backend.isIdle());
if (!backend.isConnected()) {
// Clear out the status color.
this.setStatusColorForState("");
}
}
@Override
public void controlStateChange(UGSEvent.ControlState state) {
}
@Override
public void fileStreamComplete(String filename, boolean success) {
}
@Override
public void commandSkipped(GcodeCommand command) {
}
@Override
public void commandSent(GcodeCommand command) {
}
@Override
public void commandComment(String comment) {
latestCommentValueLabel.setText(comment);
}
@Override
public void probeCoordinates(Position p) {
}
@Override
public void commandComplete(GcodeCommand command) {
}
@Override
public void messageForConsole(MessageType type, String msg) {
}
@Override
public void postProcessData(int numRows) {
}
@Override
public void statusStringListener(ControllerStatus status) {
this.activeStateValueLabel.setText( status.getState() );
this.setStatusColorForState( status.getState() );
if (status.getEnabledPins() != null) {
if (!addedPinStatusPanel) {
addedPinStatusPanel = true;
add(pinStatusPanel, "span 2");
this.repaint();
}
EnabledPins ep = status.getEnabledPins();
pinX.setSelected(ep.X);
pinY.setSelected(ep.Y);
pinZ.setSelected(ep.Z);
pinProbe.setSelected(ep.Probe);
pinDoor.setSelected(ep.Door);
pinHold.setSelected(ep.Hold);
pinSoftReset.setSelected(ep.SoftReset);
pinCycleStart.setSelected(ep.CycleStart);
}
if (status.getMachineCoord() != null) {
this.setUnits(status.getMachineCoord().getUnits());
this.setPostionValueColor(this.machinePositionXValue, status.getMachineCoord().x);
this.machinePositionXValue.setText(decimalFormatter.format(status.getMachineCoord().x));
this.setPostionValueColor(this.machinePositionYValue, status.getMachineCoord().y);
this.machinePositionYValue.setText(decimalFormatter.format(status.getMachineCoord().y));
this.setPostionValueColor(this.machinePositionZValue, status.getMachineCoord().z);
this.machinePositionZValue.setText(decimalFormatter.format(status.getMachineCoord().z));
}
if (status.getWorkCoord() != null) {
this.setUnits(status.getWorkCoord().getUnits());
this.setPostionValueColor(this.workPositionXValue, status.getWorkCoord().x);
this.workPositionXValue.setText(decimalFormatter.format(status.getWorkCoord().x));
this.setPostionValueColor(this.workPositionYValue, status.getWorkCoord().y);
this.workPositionYValue.setText(decimalFormatter.format(status.getWorkCoord().y));
this.setPostionValueColor(this.workPositionZValue, status.getWorkCoord().z);
this.workPositionZValue.setText(decimalFormatter.format(status.getWorkCoord().z));
}
}
private void setPostionValueColor(JLabel label, double newValue) {
if (!label.getText().equals(decimalFormatter.format(newValue))) {
label.setForeground(Color.red);
} else {
label.setForeground(Color.black);
}
}
private void setStatusColorForState(String state) {
if (backend.getSettings().isDisplayStateColor()) {
java.awt.Color color = null; // default to a transparent background.
if (state.equals(Localization.getString("mainWindow.status.alarm"))) {
color = Color.RED;
} else if (state.equals(Localization.getString("mainWindow.status.hold"))) {
color = Color.YELLOW;
} else if (state.equals(Localization.getString("mainWindow.status.queue"))) {
color = Color.YELLOW;
} else if (state.equals(Localization.getString("mainWindow.status.run"))) {
color = Color.GREEN;
} else {
color = Color.WHITE;
}
this.activeStateLabel.setBackground(color);
this.activeStateValueLabel.setBackground(color);
} else {
this.activeStateLabel.setBackground(null);
this.activeStateValueLabel.setBackground(null);
}
}
private void resetCoordinateButton(char coord) {
try {
this.backend.resetCoordinateToZero(coord);
} catch (Exception ex) {
displayErrorDialog(ex.getMessage());
}
}
}