Skip to content

Commit f1fbaca

Browse files
authored
Fixed visualization (#2754)
1 parent 0756a1b commit f1fbaca

File tree

13 files changed

+225
-130
lines changed

13 files changed

+225
-130
lines changed
File renamed without changes.

ugs-fx/src/main/java/com/willwinder/universalgcodesender/fx/Main.java

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
import com.willwinder.ugs.nbp.dro.MachineStatusTopComponent;
55
import com.willwinder.ugs.nbp.jog.JogTopComponent;
66
import com.willwinder.ugs.nbp.lib.lookup.CentralLookup;
7+
import com.willwinder.universalgcodesender.fx.actions.ActionRegistry;
8+
import com.willwinder.universalgcodesender.fx.actions.StartAction;
79
import com.willwinder.universalgcodesender.fx.component.ToolBarMenu;
10+
import com.willwinder.universalgcodesender.fx.helper.SvgLoader;
811
import com.willwinder.universalgcodesender.fx.visualizer.Visualizer;
912
import com.willwinder.universalgcodesender.model.BackendAPI;
13+
import com.willwinder.universalgcodesender.pendantui.PendantUI;
1014
import com.willwinder.universalgcodesender.utils.Settings;
1115
import com.willwinder.universalgcodesender.utils.SettingsFactory;
1216
import com.willwinder.universalgcodesender.utils.Version;
@@ -16,7 +20,9 @@
1620
import javafx.geometry.Orientation;
1721
import javafx.scene.Scene;
1822
import javafx.scene.control.SplitPane;
19-
import javafx.scene.image.Image;
23+
import javafx.scene.input.KeyCode;
24+
import javafx.scene.input.KeyCodeCombination;
25+
import javafx.scene.input.KeyCombination;
2026
import javafx.scene.layout.Priority;
2127
import javafx.scene.layout.StackPane;
2228
import javafx.scene.layout.VBox;
@@ -30,12 +36,12 @@
3036
public class Main extends Application {
3137
private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
3238
private static Settings settings;
39+
private final VBox root = new VBox();
3340

3441
@Override
3542
public void start(Stage primaryStage) {
3643
initialize(primaryStage);
3744

38-
3945
ToolBarMenu toolBarMenu = new ToolBarMenu();
4046

4147
SwingNode machineStatusPanel = new SwingNode();
@@ -65,35 +71,47 @@ public void start(Stage primaryStage) {
6571

6672

6773
// ===== Top-level Layout =====
68-
VBox root = new VBox();
6974
root.getChildren().addAll(toolBarMenu, splitPane);
7075
VBox.setVgrow(splitPane, Priority.ALWAYS); // Make splitPane expand
7176

7277

7378
// ===== Scene and Stage =====
7479
Scene scene = new Scene(root);
7580
primaryStage.setTitle("Universal G-code Sender - " + Version.getVersion());
76-
primaryStage.getIcons().add(new Image("icons/icon.png"));
81+
SvgLoader.loadIcon("icons/ugs.svg", 128).ifPresent(icon -> primaryStage.getIcons().add(icon));
7782
primaryStage.setScene(scene);
7883
primaryStage.show();
7984

85+
registerShortCuts(scene);
86+
87+
8088
splitPaneDivider.setPosition(settings.getFxSettings().getDividerContentPercent());
8189
splitPaneDivider.positionProperty().addListener((obs, oldVal, newVal) -> settings.getFxSettings().setDividerContentPercent(newVal.doubleValue()));
8290

8391
Parameters params = getParameters();
8492
if (!params.getUnnamed().isEmpty()) {
8593
BackendAPI backendAPI = CentralLookup.getDefault().lookup(BackendAPI.class);
8694
try {
87-
backendAPI.setGcodeFile(new File(params.getUnnamed().get(0)));
95+
File file = new File(params.getUnnamed().get(0));
96+
backendAPI.setGcodeFile(file);
97+
backendAPI.getSettings().setLastWorkingDirectory(file.getParent());
8898
} catch (Exception e) {
8999
throw new RuntimeException(e);
90100
}
91101
}
92102
}
93103

104+
private void registerShortCuts(Scene scene) {
105+
KeyCombination kc = new KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN);
106+
scene.getAccelerators().put(kc, () -> ActionRegistry.getInstance()
107+
.getAction(StartAction.class.getCanonicalName())
108+
.ifPresent(a -> a.handle(null)));
109+
}
110+
94111
private void initialize(Stage primaryStage) {
95112
try {
96-
settings = SettingsFactory.loadSettings();
113+
BackendAPI backendAPI = CentralLookup.getDefault().lookup(BackendAPI.class);
114+
settings = backendAPI.getSettings();
97115
primaryStage.setWidth(settings.getFxSettings().getWindowWidth());
98116
primaryStage.setHeight(settings.getFxSettings().getWindowHeight());
99117
primaryStage.setX(settings.getFxSettings().getWindowPositionX());
@@ -110,6 +128,8 @@ private void initialize(Stage primaryStage) {
110128
e.printStackTrace();
111129
}
112130

131+
primaryStage.setOnShown(e -> root.requestFocus());
132+
113133
// Exit when the window is closed
114134
primaryStage.setOnCloseRequest(event -> {
115135
settings.getFxSettings().setWindowWidth((int) primaryStage.getWidth());
@@ -121,6 +141,13 @@ private void initialize(Stage primaryStage) {
121141
Platform.exit(); // Clean shutdown of the application thread
122142
System.exit(0); // Optional: force the JVM to exit
123143
});
144+
145+
146+
if (settings.isAutoStartPendant()) {
147+
BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class);
148+
PendantUI pendantUI = new PendantUI(backend);
149+
pendantUI.start();
150+
}
124151
}
125152

126153
public static void main(String[] args) {

ugs-fx/src/main/java/com/willwinder/universalgcodesender/fx/actions/OpenFileAction.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.willwinder.ugs.nbp.lib.lookup.CentralLookup;
44
import com.willwinder.universalgcodesender.model.BackendAPI;
5-
import com.willwinder.universalgcodesender.utils.SettingsFactory;
5+
import com.willwinder.universalgcodesender.model.UGSEvent;
6+
import com.willwinder.universalgcodesender.model.events.ControllerStateEvent;
7+
import com.willwinder.universalgcodesender.model.events.FileStateEvent;
68
import javafx.event.ActionEvent;
79
import javafx.scene.Node;
810
import javafx.stage.FileChooser;
@@ -13,31 +15,42 @@
1315

1416
public class OpenFileAction extends BaseAction {
1517

18+
private final BackendAPI backend;
19+
1620
public OpenFileAction() {
1721
titleProperty().set("Open");
1822
iconProperty().set("icons/open.svg");
23+
24+
backend = CentralLookup.getDefault().lookup(BackendAPI.class);
25+
backend.addUGSEventListener(this::onEvent);
26+
enabledProperty().set(!backend.isConnected() || backend.isIdle());
27+
}
28+
29+
private void onEvent(UGSEvent event) {
30+
if (event instanceof ControllerStateEvent || event instanceof FileStateEvent) {
31+
enabledProperty().set(!backend.isConnected() || backend.isIdle());
32+
}
1933
}
2034

2135
@Override
2236
public void handle(ActionEvent event) {
37+
BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class);
2338
FileChooser fileChooser = new FileChooser();
2439
fileChooser.setTitle("Open Resource File");
25-
fileChooser.setInitialDirectory(new File(SettingsFactory.loadSettings().getLastWorkingDirectory()));
40+
fileChooser.setInitialDirectory(new File(backend.getSettings().getLastWorkingDirectory()));
2641
fileChooser.getExtensionFilters().addAll(
2742
new FileChooser.ExtensionFilter("Gcode files", "*.nc", "*.txt", "*.gcode"));
2843

2944
Window window = ((Node) event.getSource()).getScene().getWindow();
3045

3146
File selectedFile = fileChooser.showOpenDialog(window);
3247
if (selectedFile != null) {
33-
System.out.println(selectedFile.getAbsolutePath());
34-
BackendAPI backendAPI = CentralLookup.getDefault().lookup(BackendAPI.class);
3548
try {
36-
backendAPI.setGcodeFile(selectedFile);
49+
backend.setGcodeFile(selectedFile);
50+
backend.getSettings().setLastWorkingDirectory(selectedFile.getParent());
3751
} catch (Exception e) {
3852
throw new RuntimeException(e);
3953
}
4054
}
41-
4255
}
4356
}

ugs-fx/src/main/java/com/willwinder/universalgcodesender/fx/component/ToolBarMenu.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.willwinder.ugs.nbp.core.actions.ConnectDisconnectAction;
44
import com.willwinder.ugs.nbp.core.actions.PauseAction;
5+
import com.willwinder.ugs.nbp.core.actions.SoftResetAction;
56
import com.willwinder.ugs.nbp.core.actions.StopAction;
7+
import com.willwinder.ugs.nbp.core.actions.UnlockAction;
68
import com.willwinder.universalgcodesender.fx.actions.ActionRegistry;
79
import com.willwinder.universalgcodesender.fx.actions.OpenFileAction;
810
import com.willwinder.universalgcodesender.fx.actions.StartAction;
@@ -21,9 +23,13 @@ public ToolBarMenu() {
2123
createButton(ConnectDisconnectAction.class).ifPresent(children::add);
2224
children.add(new Separator());
2325
createButton(OpenFileAction.class).ifPresent(children::add);
26+
children.add(new Separator());
2427
createButton(StartAction.class).ifPresent(children::add);
2528
createButton(PauseAction.class).ifPresent(children::add);
2629
createButton(StopAction.class).ifPresent(children::add);
30+
children.add(new Separator());
31+
createButton(UnlockAction.class).ifPresent(children::add);
32+
createButton(SoftResetAction.class).ifPresent(children::add);
2733

2834
ToolBar toolBar = new ToolBar();
2935
toolBar.getItems().addAll(children);
@@ -35,6 +41,10 @@ private Optional<Node> createButton(Class<?> actionClass) {
3541
return ActionRegistry
3642
.getInstance()
3743
.getAction(actionClass.getCanonicalName())
38-
.map(ActionButton::new);
44+
.map(action -> {
45+
ActionButton actionButton = new ActionButton(action, ActionButton.SIZE_LARGE);
46+
actionButton.setShowText(false);
47+
return actionButton;
48+
});
3949
}
4050
}
Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,58 @@
11
package com.willwinder.universalgcodesender.fx.control;
22

33
import com.willwinder.universalgcodesender.fx.actions.Action;
4-
import static com.willwinder.universalgcodesender.fx.helper.SvgLoader.loadIcon;
4+
import javafx.beans.property.BooleanProperty;
5+
import javafx.beans.property.IntegerProperty;
6+
import javafx.beans.property.SimpleBooleanProperty;
7+
import javafx.beans.property.SimpleIntegerProperty;
58
import javafx.scene.control.Button;
9+
import javafx.scene.control.Tooltip;
610
import javafx.scene.image.ImageView;
711

12+
import static com.willwinder.universalgcodesender.fx.helper.SvgLoader.loadIcon;
13+
814
public class ActionButton extends Button {
15+
16+
public static final int SIZE_NORMAL = 24;
17+
public static final int SIZE_LARGE = 32;
18+
private final Action action;
19+
private final BooleanProperty showText = new SimpleBooleanProperty(true);
20+
private final IntegerProperty iconSize = new SimpleIntegerProperty(SIZE_NORMAL);
21+
922
public ActionButton(Action action) {
10-
// Register listeners
23+
this(action, SIZE_NORMAL);
24+
}
25+
26+
public ActionButton(Action action, int size) {
27+
this.action = action;
28+
this.iconSize.setValue(size);
29+
1130
setOnAction(action);
1231
registerPropertyListeners(action);
1332

1433
setText(action.getTitle());
34+
setTooltip(new Tooltip(action.getTitle()));
1535
setDisable(!action.isEnabled());
1636
setIcon(action.getIcon());
1737
}
1838

39+
public void setShowText(boolean show) {
40+
showText.set(show);
41+
setText(show ? action.getTitle() : null);
42+
}
43+
1944
private void registerPropertyListeners(Action action) {
20-
action.titleProperty().addListener((v, o, n) -> setText(n));
45+
action.titleProperty().addListener((v, o, n) -> {
46+
if (showText.get()) {
47+
setText(n);
48+
}
49+
});
2150
action.enabledProperty().addListener((v, o, n) -> setDisable(!n));
2251
action.iconProperty().addListener((v, o, n) -> setIcon(n));
52+
iconSize.addListener((v, o, n) -> setIcon(action.getIcon()));
2353
}
2454

2555
private void setIcon(String iconBase) {
26-
loadIcon(iconBase, 24).ifPresent(image -> setGraphic(new ImageView(image)));
56+
loadIcon(iconBase, iconSize.get()).ifPresent(image -> setGraphic(new ImageView(image)));
2757
}
2858
}

ugs-fx/src/main/java/com/willwinder/universalgcodesender/fx/visualizer/GcodeModel.java

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,30 +70,28 @@ public GcodeModel() {
7070
getChildren().add(meshView);
7171
BackendAPI backendAPI = CentralLookup.getDefault().lookup(BackendAPI.class);
7272
gcvp = new GcodeViewParse();
73-
backendAPI.addUGSEventListener(event -> {
74-
ThreadHelper.invokeLater(() -> {
75-
if (event instanceof FileStateEvent) {
76-
if (((FileStateEvent) event).getFileState() == FileState.FILE_LOADED) {
77-
78-
try {
79-
List<LineSegment> lineSegments = loadModel(gcvp, backendAPI.getGcodeFile().getAbsolutePath());
80-
TriangleMesh mesh = pointsToMesh(lineSegments);
81-
meshView.setMesh(mesh);
82-
} catch (Exception e) {
83-
e.printStackTrace();
84-
}
85-
73+
backendAPI.addUGSEventListener(event -> ThreadHelper.invokeLater(() -> {
74+
if (event instanceof FileStateEvent) {
75+
if (((FileStateEvent) event).getFileState() == FileState.FILE_LOADED) {
76+
77+
try {
78+
List<LineSegment> lineSegments = loadModel(gcvp, backendAPI.getGcodeFile().getAbsolutePath());
79+
TriangleMesh mesh = pointsToMesh(lineSegments);
80+
meshView.setMesh(mesh);
81+
} catch (Exception e) {
82+
e.printStackTrace();
8683
}
84+
8785
}
88-
});
89-
});
86+
}
87+
}));
9088

9189

9290
}
9391

9492
private TriangleMesh pointsToMesh(List<LineSegment> lineSegments) {
9593
TriangleMesh mesh = new TriangleMesh();
96-
float width = 0.03f; // Thin width for visual line approximation
94+
float width = 0.05f; // Thin width for visual line approximation
9795

9896
for (int i = 0; i < lineSegments.size(); i++) {
9997
LineSegment lineSegment = lineSegments.get(i);
@@ -104,7 +102,7 @@ private TriangleMesh pointsToMesh(List<LineSegment> lineSegments) {
104102
Point3D dir = p2.substract(p1).normalize();
105103
Point3D perp = dir.crossProduct(ZERO.add(0, 0, 1)).normalize().multiply(width);
106104
if (perp.magnitude() == 0) { // If dir is parallel to Z, use X axis
107-
perp = new Point3D(width, 0, 0);
105+
perp = new Point3D(width, 0, width);
108106
}
109107

110108
// Add 4 points for the rectangle

ugs-fx/src/main/java/com/willwinder/universalgcodesender/fx/visualizer/Tool.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,21 @@ public Tool() {
2525
BackendAPI backendAPI = CentralLookup.getDefault().lookup(BackendAPI.class);
2626
backendAPI.addUGSEventListener(this::onEvent);
2727

28-
MeshView cone = createCone(5, 10, 10, Color.YELLOW);
28+
MeshView cone = createCone(4, 10, 16, Color.ORANGE);
2929
cone.setRotationAxis(Rotate.X_AXIS);
3030
cone.setRotate(90);
31-
setTranslateZ(5);
31+
cone.setTranslateZ(5);
3232

33-
getChildren().add(cone);
33+
MeshView coneTop = createCone(4, 2, 16, Color.ORANGE);
34+
coneTop.setRotationAxis(Rotate.X_AXIS);
35+
coneTop.setRotate(-90);
36+
coneTop.setTranslateZ(11);
3437

35-
cone.translateXProperty().bind(posX);
36-
cone.translateYProperty().bind(posY);
37-
cone.translateZProperty().bind(posZ);
38+
getChildren().addAll(cone, coneTop);
3839

40+
translateXProperty().bind(posX);
41+
translateYProperty().bind(posY);
42+
translateZProperty().bind(posZ);
3943
}
4044

4145
private void onEvent(UGSEvent ugsEvent) {

0 commit comments

Comments
 (0)