/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.cirqwizard.fx.machining; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.Cursor; import javafx.scene.control.*; import javafx.scene.input.*; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import org.cirqwizard.fx.Context; import org.cirqwizard.fx.PCBPane; import org.cirqwizard.fx.SettingsDependentScreenController; import org.cirqwizard.fx.services.SerialInterfaceService; import org.cirqwizard.generation.toolpath.Toolpath; import org.cirqwizard.layers.Board; import java.net.URL; import java.util.List; import java.util.ResourceBundle; import java.util.stream.Collectors; public abstract class Machining extends SettingsDependentScreenController implements Initializable { @FXML protected PCBPane pcbPane; @FXML protected ScrollPane scrollPane; @FXML protected Button goButton; @FXML protected Button showGCodeButton; @FXML protected Region veil; @FXML protected VBox gcodePane; @FXML protected TextArea gcodeListing; @FXML protected VBox executionPane; @FXML protected ProgressBar executionProgressBar; @FXML protected Label timeElapsedLabel; private SerialInterfaceService serialService; @Override protected String getFxmlName() { return "/org/cirqwizard/fx/machining/Machining.fxml"; } @Override public void initialize(URL url, ResourceBundle resourceBundle) { scrollPane.addEventFilter(ScrollEvent.ANY, (event) -> { if (event.isShortcutDown()) { double scale = pcbPane.scaleProperty().getValue() + event.getDeltaY() / 10000.0; scale = Math.max(scale, 0.005); scale = Math.min(scale, 1); pcbPane.scaleProperty().setValue(scale); event.consume(); } }); view.addEventFilter(KeyEvent.ANY, event -> pcbPane.setCursor(!event.isShortcutDown() ? Cursor.CROSSHAIR : Cursor.DEFAULT)); PCBPaneMouseHandler mouseHandler = new PCBPaneMouseHandler(pcbPane); mouseHandler.toolpathsProperty().bind(pcbPane.toolpathsProperty()); pcbPane.addEventFilter(MouseEvent.ANY, mouseHandler); gcodePane.addEventFilter(KeyEvent.KEY_PRESSED, event -> { if (event.getCode() == KeyCode.ESCAPE) { hideGCodeListing(); event.consume(); } }); } protected abstract void generateToolpaths(); @Override public void settingsInvalidated() { generateToolpaths(); } private class ShortcutHandler implements EventHandler<KeyEvent> { private final KeyCombination keyEnable = new KeyCodeCombination(KeyCode.E, KeyCombination.SHORTCUT_DOWN); private final KeyCombination keyDisable = new KeyCodeCombination(KeyCode.D, KeyCombination.SHORTCUT_DOWN); private final KeyCombination keySelectAll = new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN); private final KeyCodeCombination keyZoomIn = new KeyCodeCombination(KeyCode.EQUALS, KeyCombination.SHORTCUT_DOWN); private final KeyCodeCombination keyZoomOut = new KeyCodeCombination(KeyCode.MINUS, KeyCombination.SHORTCUT_DOWN); private final KeyCodeCombination keyFlipHorizontal = new KeyCodeCombination(KeyCode.M, KeyCombination.SHORTCUT_DOWN); @Override public void handle(KeyEvent event) { if (event.isConsumed()) return; if (keyEnable.match(event)) { enableSelected(); event.consume(); } else if (keyDisable.match(event)) { disableSelected(); event.consume(); } else if (keySelectAll.match(event)) { selectAll(); event.consume(); } else if (keyZoomIn.match(event)) { zoomIn(); event.consume(); } else if (keyZoomOut.match(event)) { zoomOut(); event.consume(); } else if (keyFlipHorizontal.match(event)) { flipHorizontal(); event.consume(); } } } private ShortcutHandler shortcutHandler = new ShortcutHandler(); @Override public EventHandler<? super KeyEvent> getShortcutHandler() { return shortcutHandler; } @Override public void refresh() { Context context = getMainApplication().getContext(); serialService = new SerialInterfaceService(getMainApplication()); if (!goButton.disableProperty().isBound()) goButton.setDisable(isRunningDisabled()); showGCodeButton.setDisable(isWcsDefined()); executionProgressBar.progressProperty().bind(serialService.progressProperty()); timeElapsedLabel.textProperty().bind(serialService.executionTimeProperty()); executionPane.visibleProperty().bind(serialService.runningProperty()); pcbPane.setBoardWidth(context.getPanel().getSize().getWidth()); pcbPane.setBoardHeight(context.getPanel().getSize().getHeight()); pcbPane.toolpathsProperty().setValue(null); pcbPane.repaint(); generateToolpaths(); pcbPane.repaint(); } protected boolean isRunningDisabled() { return getMainApplication().getCNCController() == null || isWcsDefined(); } private boolean isWcsDefined() { return getMainApplication().getContext().getG54X() == null || getMainApplication().getContext().getG54Y() == null || getMainApplication().getContext().getG54Z() == null; } public void zoomIn() { double scale = pcbPane.scaleProperty().getValue() + 0.005; scale = Math.max(scale, 0.005); scale = Math.min(scale, 0.045); pcbPane.scaleProperty().setValue(scale); } public void zoomOut() { double scale = pcbPane.scaleProperty().getValue() - 0.005; scale = Math.max(scale, 0.005); scale = Math.min(scale, 0.045); pcbPane.scaleProperty().setValue(scale); } public void flipHorizontal() { pcbPane.setFlipHorizontal(!pcbPane.isFlipHorizontal()); } protected abstract Board.LayerType getCurrentLayer(); public void selectAll() { pcbPane.toolpathsProperty().getValue().stream().forEach(t -> t.setSelected(true)); pcbPane.repaint(pcbPane.toolpathsProperty().getValue()); } public void enableSelected() { List<Toolpath> changedToolpaths = pcbPane.toolpathsProperty().getValue().stream(). filter(Toolpath::isSelected).collect(Collectors.toList()); changedToolpaths.forEach(t -> { t.setEnabled(true); t.setSelected(false); }); pcbPane.repaint(changedToolpaths); } public void disableSelected() { List<Toolpath> changedToolpaths = pcbPane.toolpathsProperty().getValue().stream(). filter(Toolpath::isSelected).collect(Collectors.toList()); changedToolpaths.forEach(toolpath -> { toolpath.setEnabled(false); toolpath.setSelected(false); }); pcbPane.repaint(changedToolpaths); } protected abstract String generateGCode(); public void showGCodeListing() { veil.visibleProperty().unbind(); veil.setVisible(true); gcodePane.setVisible(true); gcodeListing.setText(generateGCode()); gcodeListing.requestFocus(); } public void hideGCodeListing() { gcodePane.setVisible(false); veil.visibleProperty().bind(serialService.runningProperty()); } public void executeProgram() { veil.visibleProperty().bind(serialService.runningProperty()); serialService.setProgram(generateGCode()); serialService.restart(); } public void stopExecution() { serialService.cancel(); } public void stopGeneration() { } }