kopia lustrzana https://github.com/jameshball/osci-render
Add placeholder when no previous projects
rodzic
a068492a0d
commit
655f2ee90a
|
@ -1,6 +1,6 @@
|
|||
package sh.ball.gui;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ExceptionConsumer<T> {
|
||||
void accept(T value) throws Exception;
|
||||
public interface ExceptionBiConsumer<T, S> {
|
||||
void accept(T value1, S value2) throws Exception;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ public class Gui extends Application {
|
|||
root = loader.load();
|
||||
MainController controller = loader.getController();
|
||||
|
||||
projectSelectController.setApplicationLauncher(path -> launchMainApplication(controller, path));
|
||||
projectSelectController.setApplicationLauncher((path, muted) -> launchMainApplication(controller, path, muted));
|
||||
|
||||
controller.setAddRecentFile(projectSelectController::addRecentFile);
|
||||
|
||||
|
@ -172,9 +172,12 @@ public class Gui extends Application {
|
|||
editor.setCallback(controller::updateFileData);
|
||||
}
|
||||
|
||||
public void launchMainApplication(MainController controller, String projectPath) throws Exception {
|
||||
public void launchMainApplication(MainController controller, String projectPath, Boolean muted) throws Exception {
|
||||
scene.setRoot(root);
|
||||
controller.openProject(projectPath);
|
||||
if (muted) {
|
||||
controller.setVolume(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void launchCodeEditor(String code, String fileName) {
|
||||
|
|
|
@ -321,4 +321,8 @@ public class EffectsController implements Initializable, SubController {
|
|||
public void disableMouseTranslate() {
|
||||
translateCheckBox.setSelected(false);
|
||||
}
|
||||
|
||||
public void setVolume(double volumeValue) {
|
||||
volume.controller.slider.setValue(volumeValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1433,6 +1433,10 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
|
|||
this.addRecentFile = addRecentFile;
|
||||
}
|
||||
|
||||
public void setVolume(double volume) {
|
||||
effectsController.setVolume(volume);
|
||||
}
|
||||
|
||||
private record PrintableSlider(Slider slider) {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
@ -1,142 +1,146 @@
|
|||
package sh.ball.gui.controller;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.web.WebView;
|
||||
import netscape.javascript.JSObject;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.events.EventTarget;
|
||||
import org.w3c.dom.html.HTMLAnchorElement;
|
||||
import sh.ball.gui.ExceptionConsumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static sh.ball.gui.Gui.logger;
|
||||
|
||||
public class ProjectSelectController implements Initializable {
|
||||
|
||||
private static final int MAX_ITEMS = 20;
|
||||
private static final String RECENT_FILE = "RECENT_FILE_";
|
||||
|
||||
private final Preferences userPreferences = Preferences.userNodeForPackage(getClass());
|
||||
private final ObservableList<String> recentFiles = FXCollections.observableArrayList();
|
||||
private ExceptionConsumer<String> launchMainApplication;
|
||||
private Consumer<String> openBrowser;
|
||||
|
||||
@FXML
|
||||
private ListView<String> recentFilesListView;
|
||||
@FXML
|
||||
private Button newProjectButton;
|
||||
@FXML
|
||||
private CheckBox startMutedCheckBox;
|
||||
@FXML
|
||||
private WebView changelogWebView;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
for (int i = 0; i < MAX_ITEMS; i++) {
|
||||
String path = userPreferences.get(RECENT_FILE + i, null);
|
||||
if (path != null) {
|
||||
recentFiles.add(path);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recentFilesListView.setItems(recentFiles);
|
||||
recentFilesListView.setOnMouseClicked(e -> {
|
||||
try {
|
||||
launchMainApplication.accept(recentFilesListView.getSelectionModel().getSelectedItem());
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
|
||||
newProjectButton.setOnAction(e -> {
|
||||
try {
|
||||
launchMainApplication.accept(null);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
String changelogHtml = new String(getClass().getResourceAsStream("/html/changelog.html").readAllBytes(), StandardCharsets.UTF_8);
|
||||
changelogWebView.getEngine().loadContent(changelogHtml);
|
||||
InputStream changelogInputStream = getClass().getResourceAsStream("/CHANGELOG.md");
|
||||
String changelog = new String(changelogInputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
changelogWebView.getEngine().getLoadWorker().stateProperty().addListener((e, old, state) -> {
|
||||
if (state == Worker.State.SUCCEEDED) {
|
||||
JSObject window = (JSObject) changelogWebView.getEngine().executeScript("window");
|
||||
window.setMember("changelog", changelog);
|
||||
changelogWebView.getEngine().executeScript(
|
||||
"document.getElementById('content').innerHTML = marked.parse(changelog);"
|
||||
);
|
||||
Document document = changelogWebView.getEngine().getDocument();
|
||||
NodeList nodeList = document.getElementsByTagName("a");
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node= nodeList.item(i);
|
||||
EventTarget eventTarget = (EventTarget) node;
|
||||
eventTarget.addEventListener("click", evt -> {
|
||||
EventTarget target = evt.getCurrentTarget();
|
||||
HTMLAnchorElement anchorElement = (HTMLAnchorElement) target;
|
||||
String href = anchorElement.getHref();
|
||||
openBrowser.accept(href);
|
||||
evt.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRecentFile(String path) {
|
||||
int index = recentFiles.indexOf(path);
|
||||
if (index == -1) {
|
||||
userPreferences.get(RECENT_FILE + recentFiles.size(), path);
|
||||
recentFiles.add(0, path);
|
||||
if (recentFiles.size() > MAX_ITEMS) {
|
||||
recentFiles.remove(recentFiles.size() - 1);
|
||||
}
|
||||
} else {
|
||||
recentFiles.remove(index);
|
||||
recentFiles.add(0, path);
|
||||
}
|
||||
resetRecentFiles();
|
||||
}
|
||||
|
||||
private void resetRecentFiles() {
|
||||
for (int i = 0; i < MAX_ITEMS; i++) {
|
||||
userPreferences.remove(RECENT_FILE + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < recentFiles.size(); i++) {
|
||||
userPreferences.put(RECENT_FILE + i, recentFiles.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void setApplicationLauncher(ExceptionConsumer<String> launchMainApplication) {
|
||||
this.launchMainApplication = launchMainApplication;
|
||||
}
|
||||
|
||||
public void setOpenBrowser(Consumer<String> openBrowser) {
|
||||
this.openBrowser = openBrowser;
|
||||
}
|
||||
}
|
||||
package sh.ball.gui.controller;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.web.WebView;
|
||||
import netscape.javascript.JSObject;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.events.EventTarget;
|
||||
import org.w3c.dom.html.HTMLAnchorElement;
|
||||
import sh.ball.gui.ExceptionBiConsumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static sh.ball.gui.Gui.logger;
|
||||
|
||||
public class ProjectSelectController implements Initializable {
|
||||
|
||||
private static final int MAX_ITEMS = 20;
|
||||
private static final String RECENT_FILE = "RECENT_FILE_";
|
||||
private static final String START_MUTED = "START_MUTED";
|
||||
|
||||
private final Preferences userPreferences = Preferences.userNodeForPackage(getClass());
|
||||
private final ObservableList<String> recentFiles = FXCollections.observableArrayList();
|
||||
private ExceptionBiConsumer<String, Boolean> launchMainApplication;
|
||||
private Consumer<String> openBrowser;
|
||||
|
||||
@FXML
|
||||
private ListView<String> recentFilesListView;
|
||||
@FXML
|
||||
private Button newProjectButton;
|
||||
@FXML
|
||||
private CheckBox startMutedCheckBox;
|
||||
@FXML
|
||||
private WebView changelogWebView;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
for (int i = 0; i < MAX_ITEMS; i++) {
|
||||
String path = userPreferences.get(RECENT_FILE + i, null);
|
||||
if (path != null) {
|
||||
recentFiles.add(path);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recentFilesListView.setItems(recentFiles);
|
||||
recentFilesListView.setOnMouseClicked(e -> {
|
||||
try {
|
||||
launchMainApplication.accept(recentFilesListView.getSelectionModel().getSelectedItem(), startMutedCheckBox.isSelected());
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
|
||||
newProjectButton.setOnAction(e -> {
|
||||
try {
|
||||
launchMainApplication.accept(null, startMutedCheckBox.isSelected());
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
|
||||
startMutedCheckBox.setSelected(userPreferences.getBoolean(START_MUTED, false));
|
||||
startMutedCheckBox.selectedProperty().addListener((e, old, startMuted) -> userPreferences.putBoolean(START_MUTED, startMuted));
|
||||
|
||||
try {
|
||||
String changelogHtml = new String(getClass().getResourceAsStream("/html/changelog.html").readAllBytes(), StandardCharsets.UTF_8);
|
||||
changelogWebView.getEngine().loadContent(changelogHtml);
|
||||
InputStream changelogInputStream = getClass().getResourceAsStream("/CHANGELOG.md");
|
||||
String changelog = new String(changelogInputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
changelogWebView.getEngine().getLoadWorker().stateProperty().addListener((e, old, state) -> {
|
||||
if (state == Worker.State.SUCCEEDED) {
|
||||
JSObject window = (JSObject) changelogWebView.getEngine().executeScript("window");
|
||||
window.setMember("changelog", changelog);
|
||||
changelogWebView.getEngine().executeScript(
|
||||
"document.getElementById('content').innerHTML = marked.parse(changelog);"
|
||||
);
|
||||
Document document = changelogWebView.getEngine().getDocument();
|
||||
NodeList nodeList = document.getElementsByTagName("a");
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node= nodeList.item(i);
|
||||
EventTarget eventTarget = (EventTarget) node;
|
||||
eventTarget.addEventListener("click", evt -> {
|
||||
EventTarget target = evt.getCurrentTarget();
|
||||
HTMLAnchorElement anchorElement = (HTMLAnchorElement) target;
|
||||
String href = anchorElement.getHref();
|
||||
openBrowser.accept(href);
|
||||
evt.preventDefault();
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRecentFile(String path) {
|
||||
int index = recentFiles.indexOf(path);
|
||||
if (index == -1) {
|
||||
userPreferences.get(RECENT_FILE + recentFiles.size(), path);
|
||||
recentFiles.add(0, path);
|
||||
if (recentFiles.size() > MAX_ITEMS) {
|
||||
recentFiles.remove(recentFiles.size() - 1);
|
||||
}
|
||||
} else {
|
||||
recentFiles.remove(index);
|
||||
recentFiles.add(0, path);
|
||||
}
|
||||
resetRecentFiles();
|
||||
}
|
||||
|
||||
private void resetRecentFiles() {
|
||||
for (int i = 0; i < MAX_ITEMS; i++) {
|
||||
userPreferences.remove(RECENT_FILE + i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < recentFiles.size(); i++) {
|
||||
userPreferences.put(RECENT_FILE + i, recentFiles.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void setApplicationLauncher(ExceptionBiConsumer<String, Boolean> launchMainApplication) {
|
||||
this.launchMainApplication = launchMainApplication;
|
||||
}
|
||||
|
||||
public void setOpenBrowser(Consumer<String> openBrowser) {
|
||||
this.openBrowser = openBrowser;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,4 +385,10 @@
|
|||
-fx-border-width: 1px;
|
||||
-fx-border-radius: 0;
|
||||
-fx-border-color: white;
|
||||
}
|
||||
|
||||
.white-border {
|
||||
-fx-border-width: 1px;
|
||||
-fx-border-radius: 0;
|
||||
-fx-border-color: white;
|
||||
}
|
|
@ -63,7 +63,7 @@
|
|||
</AnchorPane>
|
||||
<EffectComponentGroup fx:id="translationScale" alwaysEnabled="true" increment="0.05" label="translationScale" majorTickUnit="1.0" max="10.0" min="0.0" name="Translation scale" type="TRANSLATE" value="1.0" />
|
||||
<EffectComponentGroup fx:id="translationSpeed" alwaysEnabled="true" increment="0.05" label="translationSpeed" majorTickUnit="1.0" max="10.0" min="0.0" name="Translation speed" type="TRANSLATE_SPEED" value="1.0" />
|
||||
<EffectComponentGroup fx:id="volume" alwaysEnabled="true" increment="0.05" label="volume" majorTickUnit="1.0" max="10.0" min="0.0" name="Volume scale" type="SCALE" value="3.0" />
|
||||
<EffectComponentGroup fx:id="volume" alwaysEnabled="true" increment="0.05" label="volume" majorTickUnit="1.0" max="10.0" min="0.0" name="Master volume" type="SCALE" value="3.0" />
|
||||
<EffectComponentGroup fx:id="backingMidi" alwaysEnabled="true" increment="0.005" label="visibility" majorTickUnit="0.1" max="1.0" min="0.0" name="MIDI volume" type="VISIBILITY" value="0.25" />
|
||||
<Label alignment="CENTER" prefWidth="601.0" text="Rotation" textAlignment="JUSTIFY">
|
||||
<padding>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<menus>
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<items>
|
||||
<MenuItem disable="true" mnemonicParsing="false" text="osci-render v1.26.4" />
|
||||
<MenuItem fx:id="openProjectMenuItem" mnemonicParsing="false" text="Open Project">
|
||||
<accelerator>
|
||||
<KeyCodeCombination alt="UP" code="O" control="UP" meta="UP" shift="UP" shortcut="DOWN" />
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import java.lang.String?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
|
@ -17,12 +19,27 @@
|
|||
<Image url="@../images/osci.png" />
|
||||
</image>
|
||||
</ImageView>
|
||||
<ListView fx:id="recentFilesListView" layoutX="28.0" layoutY="333.0" prefHeight="257.0" prefWidth="527.0" />
|
||||
<ListView fx:id="recentFilesListView" layoutX="28.0" layoutY="333.0" prefHeight="257.0" prefWidth="527.0" styleClass="darkPane" >
|
||||
<placeholder>
|
||||
<Label text="No recent projects. Start a new project below." />
|
||||
</placeholder>
|
||||
</ListView>
|
||||
<Button fx:id="newProjectButton" layoutX="222.0" layoutY="609.0" mnemonicParsing="false" prefHeight="40.0" prefWidth="131.0" text="Start new project" />
|
||||
<CheckBox fx:id="startMutedCheckBox" layoutX="240.0" layoutY="670.0" mnemonicParsing="false" text="Start muted" />
|
||||
<Label layoutX="188.0" layoutY="294.0" styleClass="title" text="Recently opened projects" />
|
||||
<Label layoutX="14.0" layoutY="700.0" text="v1.26.4" />
|
||||
<Label layoutX="727.0" layoutY="40.0" styleClass="title" text="Changelog" />
|
||||
<WebView fx:id="changelogWebView" layoutX="583.0" layoutY="104.0" prefHeight="590.0" prefWidth="376.0" />
|
||||
<Label layoutX="727.0" layoutY="20.0" styleClass="title" text="Changelog" />
|
||||
<AnchorPane layoutX="582.0" layoutY="65.0" prefHeight="200.0" prefWidth="376.0">
|
||||
<children>
|
||||
<WebView fx:id="changelogWebView" layoutX="2.0" layoutY="2.0" prefHeight="638.0" prefWidth="376.0" />
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
<styleClass>
|
||||
<String fx:value="white-border" />
|
||||
<String fx:value="darkPane" />
|
||||
</styleClass>
|
||||
</AnchorPane>
|
||||
</children></AnchorPane>
|
||||
</AnchorPane>
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
body {
|
||||
background-color: #111111;
|
||||
color: white;
|
||||
font-family: Arial,serif;
|
||||
font-family: Segoe UI,Frutiger,Frutiger Linotype,Dejavu Sans,Helvetica Neue,Arial,sans-serif;
|
||||
margin: 0 0.5em 0 0;
|
||||
font-size: 0.8em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue