Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Add VM options:
```bash
--add-opens java.base/java.net=com.sothawo.mapjfx --add-opens java.base/java.lang.reflect=com.jfoenix --add-exports com.google.gson/com.google.gson.internal=pl.edu.pwr.pwrinspace.poliwrocket
```

To run the application on Linux download JavaFX and add modules:
```bash
--module-path $PATH_TO_JAVAFX_SDK/lib --add-modules=javafx.controls,javafx.fxml,javafx.base,javafx.graphics,javafx.web
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package pl.edu.pwr.pwrinspace.poliwrocket.Controller;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.TabPane;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;

public class DetachedTabController implements InvalidationListener {

@FXML
private TabPane detachedTabPane;

private Stage myStage;

private static final double initWidth = 1550.4;
private static final double initHeight = 838.4;
Comment on lines 18 to 19
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mamy już 2 miejsca, w ktorych pojawiaja się te wartości. Można zrobić wspólne miejsce do jej przechowywania


public TabPane getTabPane() {
return this.detachedTabPane;
}

public void setStage(Stage stage) {
this.myStage = stage;

stage.widthProperty().addListener(this);
stage.heightProperty().addListener(this);
}

@Override
public void invalidated(Observable observable) {
if (myStage.widthProperty().equals(observable) || myStage.heightProperty().equals(observable)) {
scaleContent(myStage.getWidth() / initWidth, myStage.getHeight() / initHeight);
}
}

private void scaleContent(double scaleX, double scaleY) {
if (detachedTabPane != null) {
if(!detachedTabPane.getTransforms().isEmpty()) {
detachedTabPane.getTransforms().clear();
}
detachedTabPane.getTransforms().add(new Scale(scaleX, scaleY, 0, 0));
}
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package pl.edu.pwr.pwrinspace.poliwrocket.Controller;

import com.interactivemesh.jfx.importer.ModelImporter;
import com.interactivemesh.jfx.importer.tds.TdsModelImporter;
import com.jfoenix.controls.JFXTextArea;
import eu.hansolo.medusa.Gauge;
import eu.hansolo.tilesfx.Tile;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.scene.control.TabPane;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
Expand All @@ -21,9 +21,11 @@
import pl.edu.pwr.pwrinspace.poliwrocket.Model.MessageParser.IMessageParser;
import pl.edu.pwr.pwrinspace.poliwrocket.Model.SerialPort.ISerialPortManager;
import pl.edu.pwr.pwrinspace.poliwrocket.Thred.UI.UIThreadManager;
import pl.edu.pwr.pwrinspace.poliwrocket.Provider.DetachedWindowsProvider;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

Expand All @@ -32,6 +34,12 @@ public class MainController extends BasicController implements InvalidationListe
private static final double initWidth = 1550.4;
private static final double initHeight = 838.4;

private static final Color white = Color.WHITE ;
private static final Color bgDark = Color.rgb(11, 66, 116, 0.7);

private static final Color black = Color.BLACK;
private static final Color fgDark = Color.rgb(245, 245, 247);

@FXML
private SubScene CANIndicatorsScene;

Expand Down Expand Up @@ -199,7 +207,6 @@ public SubScene getMapScene() {
return mapScene;
}


public void initSubScenes(Collection<FXMLLoader> fxmlLoaders) {
try {
HashMap<String, Field> fields = new HashMap<>();
Expand Down Expand Up @@ -230,6 +237,8 @@ protected void initialize() {
addNodesForAppScalingPurpose();
setAppImages();
setup3DModel();

setupDetachedWindowsProvider();
}

private void setAppImages() {
Expand Down Expand Up @@ -328,6 +337,36 @@ public void invalidated(Observable observable) {
} else {
outGoing.setStyle("");
}

boolean isLight = ((Configuration) observable).isLightMode();
URL cssURL = getClass().getResource(isLight ? "/Views/constantsLight.css" : "/Views/constants.css");

if (cssURL == null) {
System.err.println("ERROR: css not found");
return;
}

String cssPath = cssURL.toExternalForm();

nodes.forEach(node -> {
applyStyleToNode(node, cssPath, isLight);
});

for (Field field : this.getClass().getDeclaredFields()) {
if (field.getName().endsWith("Scene")) {
try {
field.setAccessible(true);
Object value = field.get(this);
if (value instanceof SubScene) {
SubScene ss = (SubScene) value;
applyStyleToNode(ss, cssPath, isLight);
findAndStyleTiles(ss.getRoot(), isLight);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
} else if(primaryStage.heightProperty().equals(observable) || primaryStage.widthProperty().equals(observable)) {
scaleSubScenes(primaryStage.widthProperty().doubleValue()/initWidth,primaryStage.heightProperty().doubleValue()/initHeight);
}
Expand All @@ -342,11 +381,136 @@ private void scaleSubScenes(double scaleX, double scaleY) {
if(!scene.getTransforms().isEmpty()) {
scene.getTransforms().clear();
}

scene.getTransforms().add(new Scale(scaleX,scaleY));
scene.setLayoutX(nodesInitPositions.get(scene).getValue0() * scaleX);
scene.setLayoutY(nodesInitPositions.get(scene).getValue1() * scaleY);
});
}

private void setupDetachedWindowsProvider() {
if (tabPane != null) {
DetachedWindowsProvider.addActiveTabPane(tabPane);
}
for(int i = 0; i < Objects.requireNonNull(tabPane).getTabs().size(); i++) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Można to wciągnąc pod pierwszego ifa, który właśnie sprawdza czy tabPane nie jest nullem i na koniec dodać else jakiś z informacja o tym, ze tabPane jest nullem

Tab tab = tabPane.getTabs().get(i);
tab.setUserData(i);
configureTabContextMenu(tab);
}
}

private void configureTabContextMenu(Tab tab){
ContextMenu contextMenu = new ContextMenu();

MenuItem newWindowItem = new MenuItem("Detach to a new window");
newWindowItem.setOnAction(e -> detachTabToNewWindow(tab));
contextMenu.getItems().add(newWindowItem);

Menu moveMenu = new Menu("Move to: ");

contextMenu.setOnShowing(e ->{
moveMenu.getItems().clear();
for(TabPane tabPane: DetachedWindowsProvider.getActiveTabPanes()){
if(tabPane == tab.getTabPane()){
continue;
}
String title = ((Stage) tabPane.getScene().getWindow()).getTitle();
MenuItem item = new MenuItem(title);
item.setOnAction(ev-> {
DetachedWindowsProvider.transferTabPane(tab, tabPane);
configureTabContextMenu(tab);
});
moveMenu.getItems().add(item);
}
});
contextMenu.getItems().add(moveMenu);
tab.setContextMenu(contextMenu);
}

private void detachTabToNewWindow(Tab tab) {
tab.setUserData(tabPane.getTabs().indexOf(tab));

try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/Views/DetachedTabView.fxml"));
Parent root = loader.load();
DetachedTabController detachedController = loader.getController();

Stage stage = new Stage();
stage.setScene(new Scene(root, initWidth, initHeight));
detachedController.setStage(stage);

TabPane newTabPane = detachedController.getTabPane();
DetachedWindowsProvider.addActiveTabPane(newTabPane);
DetachedWindowsProvider.transferTabPane(tab, newTabPane);

String tabTitle = tab.getText();
stage.setTitle("SouRCE - " + tabTitle);

stage.setOnCloseRequest(e -> {
DetachedWindowsProvider.removeActiveTabPane(newTabPane);

List<Tab> tabsToReturn = new ArrayList<>(newTabPane.getTabs());
tabsToReturn.sort(Comparator.comparingInt(t -> (int) t.getUserData()));
for (Tab t : tabsToReturn) {
DetachedWindowsProvider.transferTabPane(t, this.tabPane);
configureTabContextMenu(t);
}
});
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}

private void applyStyleToNode(Node node, String cssPath, boolean isLight) {
if (node instanceof Parent) {
Parent p = (Parent) node;
p.getStylesheets().clear();
p.getStylesheets().add(cssPath);
} else if (node instanceof SubScene) {
SubScene ss = (SubScene) node;
if (ss.getRoot() != null) {
ss.getRoot().getStylesheets().clear();
ss.getRoot().getStylesheets().add(cssPath);
findAndStyleTiles(ss.getRoot(), isLight);
}else{
System.out.println("Error: Scene root cannot be null when applying styles");
}
}
}

private void findAndStyleTiles(Parent root, boolean isLight) {
Color bg = isLight ? white : bgDark;
Color fg = isLight ? black : fgDark;
for (Node n : root.getChildrenUnmodifiable()) {
if (n instanceof Tile) {
Tile tile = (Tile) n;
applyTileStyle(tile, bg, fg);
}else if (n instanceof Gauge) {
Gauge gauge = (Gauge) n;
applyGaugeStyle(gauge, fg);
}if (n.getClass().getName().startsWith("pl.edu.pwr") &&
!(n instanceof Tile || n instanceof Gauge || n instanceof Parent)) {
System.out.println("Unpredicted node ignored for styling:: " + n.getClass().getSimpleName());
}
}
}

private void applyTileStyle(Tile tile, Color bg, Color fg) {
tile.setBackgroundColor(bg);
tile.setForegroundBaseColor(fg);
tile.setTitleColor(fg);
tile.setTextColor(fg);
tile.setValueColor(fg);
tile.setUnitColor(fg);
tile.setBarColor(fg);
}

private void applyGaugeStyle(Gauge gauge, Color fg) {
gauge.setBarColor(fg);
gauge.setValueColor(fg);
gauge.setTitleColor(fg);
gauge.setUnitColor(fg);
gauge.setTickLabelColor(fg);
gauge.setNeedleColor(fg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.controls.JFXToggleButton;
import javafx.beans.Observable;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
Expand All @@ -19,6 +22,8 @@
import java.util.concurrent.Executors;

public class SettingsController extends BasicController {
@FXML
public JFXToggleButton lightModeToggle;

@FXML
private AnchorPane mainPanel;
Expand All @@ -41,6 +46,7 @@ protected void initialize() {
int initYInput = 45;
int offsetY = 40;


for (ISensor sensor : Configuration.getInstance().sensorRepository.getAllBasicSensors().values()) {
if (sensor instanceof ITare) {
var tareSensor = (ITare) sensor;
Expand Down Expand Up @@ -77,6 +83,12 @@ void apply() {
actionList.forEach(IAction::execute);
}

@FXML
private void onToggleLightMode() {
boolean isLight = lightModeToggle.isSelected();;
Configuration.getInstance().setLightMode(isLight);
}

void reloadConfig() {
try {
Configuration.getInstance().reloadConfigInstance(modelAsJsonSaveService.readFromFile(new ConfigurationSaveModel()));
Expand All @@ -88,6 +100,8 @@ void reloadConfig() {
}
}



@Override
public void invalidated(Observable observable) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ protected TextChannel getChannel(@NotNull MessageReceivedEvent event) {
}
return null;
}
}
}
7 changes: 5 additions & 2 deletions src/main/java/pl/edu/pwr/pwrinspace/poliwrocket/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ public void start(Stage primaryStage) {
.forEach(p -> {
if (p.getFileName().toString().endsWith("View.fxml")) {
try {
loaders.put(p.getFileName().toString(), new FXMLLoader(p.toUri().toURL()));
if(!p.getFileName().toString().equals("DetachedTabView.fxml")){
loaders.put(p.getFileName().toString(), new FXMLLoader(p.toUri().toURL()));
}

} catch (MalformedURLException e) {
e.printStackTrace();
}
Expand Down Expand Up @@ -215,11 +218,11 @@ public void start(Stage primaryStage) {

//Stage settings
primaryStage.setTitle("SouRCE");
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("Poliwrocket.png"))));
primaryStage.heightProperty().addListener(mainController);
primaryStage.widthProperty().addListener(mainController);
primaryStage.setMaximized(true);
primaryStage.setOnShown(windowEvent -> {
UIThreadManager.getInstance().start();
AppStateLogger.getInstance().start();
Expand Down
Loading