diff --git a/PlayWall/assets/de/tobias/playpad/assets/classic_style.css b/PlayWall/assets/de/tobias/playpad/assets/classic_style.css new file mode 100644 index 0000000000000000000000000000000000000000..135dfc913b7279684cd5f03dbb9f6db0b76d7e63 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/classic_style.css @@ -0,0 +1,19 @@ +.pad-grid { + -fx-hgap: 0px; + -fx-vgap: 0px; +} + +.pad { + -fx-padding: 4px; + -fx-spacing: 5px; + -fx-background-insets: 2px; +} + +.pad:drag { + -fx-opacity: 0.6; +} + + +.live-label { + -fx-text-fill: red !important; +} \ No newline at end of file diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/changelogDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/changelogDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..24bcd24faa2503a5829fddfd981c000a6013f7a1 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/changelogDialog.fxml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.scene.web.*?> + + +<WebView fx:id="contentView" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" /> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/errorSummaryDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/errorSummaryDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..8f793f0dd48086a72fa6b55edb4b70f184366674 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/errorSummaryDialog.fxml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <TableView fx:id="errorTable" layoutY="38.0" prefHeight="312.0" prefWidth="600.0" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="38.0"> + <columns> + <TableColumn fx:id="padColumn" prefWidth="230.0" text="%errorSummary.column.cart" /> + <TableColumn fx:id="errorColumn" prefWidth="465.0" text="%errorSummary.column.des" /> + <TableColumn fx:id="fixColumn" prefWidth="200.0" text="%errorSummary.column.solution" /> + </columns> + </TableView> + <Label layoutX="14.0" layoutY="14.0" text="%errorSummary.label.headline" /> + <Button fx:id="closeButton" layoutX="587.0" layoutY="260.0" mnemonicParsing="false" onAction="#closeButtonHandler" text="%errorSummary.button.close" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" /> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/launchDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/launchDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4b68d4f98ea2ddcf32efa55f44b663c240ffdb10 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/launchDialog.fxml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.text.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.effect.*?> +<?import javafx.scene.image.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="345.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <VBox alignment="CENTER" layoutX="24.0" layoutY="5.0" spacing="7.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="34.0" AnchorPane.topAnchor="14.0"> + <children> + <ImageView fx:id="imageView" fitHeight="144.0" fitWidth="140.0" layoutX="80.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true"> + <effect> + <DropShadow /> + </effect> + </ImageView> + <Label fx:id="infoLabel" alignment="CENTER" layoutX="24.0" layoutY="212.0" prefHeight="39.0" prefWidth="310.0" AnchorPane.leftAnchor="24.0" AnchorPane.rightAnchor="266.0" AnchorPane.topAnchor="212.0"> + <font> + <Font size="25.0" /> + </font> + </Label> + <VBox layoutX="109.0" layoutY="259.0" spacing="14.0"> + <children> + <Button fx:id="newProfileButton" layoutX="115.0" layoutY="259.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#newProfileButtonHandler" text="%launch.button.new" VBox.vgrow="ALWAYS" /> + <Button fx:id="importProfileButton" layoutX="109.0" layoutY="292.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#importProfileButtonHandler" text="%launch.button.import" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + </children> + </VBox> + <ListView id="projectList" fx:id="projectListView" fixedCellSize="40.0" layoutX="371.0" prefHeight="345.0" prefWidth="269.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="371.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <HBox layoutX="494.0" layoutY="305.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0"> + <children> + <Button fx:id="deleteButton" layoutX="494.0" layoutY="305.0" mnemonicParsing="false" onAction="#deleteButtonHandler" text="%launch.button.delete" /> + <Button fx:id="openButton" layoutX="568.0" layoutY="305.0" mnemonicParsing="false" onAction="#openButtonHandler" text="%launch.button.open" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/mappingView.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/mappingView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..1fd280d7d78644ca6efa907ef4fcc530ae4f8cd3 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/mappingView.fxml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="14.0" layoutY="9.0" spacing="14.0"> + <children> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="9.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="14.0" prefWidth="150.0" text="%mappingPreset.label.mapping" textAlignment="RIGHT" AnchorPane.leftAnchor="14.0" /> + <ComboBox fx:id="presetsListView" layoutX="169.0" layoutY="9.0" prefWidth="150.0" AnchorPane.leftAnchor="169.0" /> + </children> + </HBox> + <HBox layoutX="343.0" layoutY="9.0" spacing="14.0"> + <children> + <Button fx:id="addButton" layoutX="300.0" layoutY="9.0" mnemonicParsing="false" onAction="#addButtonHandler" text="%mappingPreset.button.add" /> + <Button fx:id="duplicateButton" layoutX="407.0" layoutY="9.0" mnemonicParsing="false" onAction="#duplicateButtonHandler" text="%mappingPreset.button.duplicate" /> + </children> + </HBox> + </children> + </HBox> + <Separator layoutY="49.0" prefHeight="3.0" prefWidth="600.0" /> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="62.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="67.0" prefWidth="150.0" text="%mappingPreset.label.name" textAlignment="RIGHT" AnchorPane.leftAnchor="14.0" /> + <TextField fx:id="nameTextField" layoutX="169.0" layoutY="62.0" prefWidth="150.0" AnchorPane.leftAnchor="169.0" /> + </children> + </HBox> + <HBox layoutY="138.0" spacing="14.0"> + <children> + <Button fx:id="exportButton" mnemonicParsing="false" onAction="#exportButtonHandler" prefWidth="150.0" text="%mappingPreset.button.export" /> + <Button fx:id="importButton" mnemonicParsing="false" onAction="#importButtonHandler" prefWidth="150.0" text="%mappingPreset.button.import" /> + <Button fx:id="removeButton" mnemonicParsing="false" onAction="#removeButtonHandler" prefWidth="150.0" text="%mappingPreset.button.delete" /> + </children> + </HBox> + <HBox alignment="BOTTOM_RIGHT" VBox.vgrow="ALWAYS"> + <children> + <Button fx:id="finishButton" mnemonicParsing="false" onAction="#finishButtonHandler" text="%mappingPreset.button.finish" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/newProfileDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/newProfileDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4825083a71d4ace4249e86fe5788d1d5321a5423 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/newProfileDialog.fxml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="100.0" prefWidth="100.0" text="%newProfile.label.name" /> + <TextField fx:id="nameTextField" minWidth="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + <Separator prefWidth="200.0" /> + <VBox fx:id="accordionParent" spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <Accordion fx:id="accordion" maxWidth="1.7976931348623157E308"> + <panes> + <TitledPane animated="false" text="%newProfile.label.midiSettings"> + <content> + <AnchorPane> + <children> + <VBox spacing="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="100.0" text="%newProfile.label.midi" /> + <CheckBox fx:id="activeCheckBox" minWidth="200.0" mnemonicParsing="false" onAction="#activeCheckBoxHandler" prefWidth="200.0" text="%settings.checkbox.activate" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="100.0" text="%settings.midi.label.device" /> + <ComboBox fx:id="midiDeviceComboBox" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + </children> + </VBox> + </children> + </AnchorPane> + </content> + </TitledPane> + </panes> + </Accordion> + </children> + </VBox> + <Separator maxWidth="1.7976931348623157E308" valignment="BOTTOM" /> + <HBox alignment="BOTTOM_RIGHT" spacing="14.0"> + <children> + <Button fx:id="cancelButton" mnemonicParsing="false" onAction="#cancelButtonHandler" text="%newProfile.button.cancel" /> + <Button fx:id="finishButton" defaultButton="true" mnemonicParsing="false" onAction="#finishButtonHandler" text="%newProfile.button.finish" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/newProjectDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/newProjectDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..f209b7e315ec0401af8b174d867a6bc170ea6843 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/newProjectDialog.fxml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="200.0" minWidth="500.0" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="100.0" prefWidth="100.0" text="%newProject.label.name" /> + <TextField fx:id="nameTextField" prefWidth="200.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="100.0" prefWidth="100.0" text="%newProject.label.profile" HBox.hgrow="NEVER" /> + <ComboBox fx:id="profileComboBox" maxWidth="1.7976931348623157E308" minWidth="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" /> + <Button fx:id="newProfileButton" mnemonicParsing="false" onAction="#newProfileButtonHandler" prefWidth="130.0" text="%newProject.button.newProfile" /> + </children> + </HBox> + <HBox prefWidth="500.0" VBox.vgrow="ALWAYS"> + <children> + <Label alignment="TOP_LEFT" text="%profile.label.info" textAlignment="JUSTIFY" wrapText="true" HBox.hgrow="ALWAYS"> + <padding> + <Insets left="114.0" /> + </padding> + </Label> + </children> + </HBox> + <Separator valignment="BOTTOM" VBox.vgrow="ALWAYS" /> + <HBox alignment="BOTTOM_RIGHT" spacing="14.0"> + <children> + <Button fx:id="cnacelButton" mnemonicParsing="false" onAction="#cancelButtonHandler" prefWidth="130.0" text="%newProject.button.cancel" /> + <Button fx:id="finishButton" defaultButton="true" mnemonicParsing="false" onAction="#finishButtonHandler" prefWidth="130.0" text="%newProject.button.finish" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/pluginView.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/pluginView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..49239259cdc8195284cd959f732b223f3a9cfd93 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/pluginView.fxml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <ListView fx:id="pluginListView" maxWidth="1.7976931348623157E308" AnchorPane.bottomAnchor="52.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" VBox.vgrow="ALWAYS" /> + <Label layoutX="407.0" layoutY="364.0" text="%plugin.label.updateInfo" wrapText="true" HBox.hgrow="ALWAYS"> + <VBox.margin> + <Insets left="14.0" right="14.0" /> + </VBox.margin> + </Label> + <Label layoutX="14.0" layoutY="365.0" text="%plugin.label.restart" wrapText="true" AnchorPane.bottomAnchor="19.0" AnchorPane.leftAnchor="14.0"> + <VBox.margin> + <Insets left="14.0" right="14.0" /> + </VBox.margin> + </Label> + <HBox alignment="TOP_RIGHT"> + <children> + <Button fx:id="finishButton" mnemonicParsing="false" onAction="#finishButtonHandler" text="%plugin.button.finish" /> + </children> + <VBox.margin> + <Insets bottom="14.0" right="14.0" /> + </VBox.margin> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/profileChooseDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/profileChooseDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..2b5338add17b385651412d338c1a79dc5c2eb402 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/profileChooseDialog.fxml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="100.0" prefWidth="100.0" text="%newProject.label.profile" HBox.hgrow="NEVER" /> + <ComboBox fx:id="profileComboBox" maxWidth="1.7976931348623157E308" minWidth="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" /> + <Button fx:id="newProfileButton" mnemonicParsing="false" onAction="#newProfileButtonHandler" prefWidth="130.0" text="%newProject.button.newProfile" /> + </children> + </HBox> + <HBox prefHeight="70.0" prefWidth="500.0" VBox.vgrow="ALWAYS"> + <children> + <Label alignment="TOP_LEFT" text="%profileChoose.label.info" wrapText="true" HBox.hgrow="ALWAYS"> + <padding> + <Insets left="114.0" /> + </padding> + </Label> + </children> + </HBox> + <Separator valignment="BOTTOM" VBox.vgrow="ALWAYS" /> + <HBox alignment="BOTTOM_RIGHT" spacing="14.0"> + <children> + <Button fx:id="cnacelButton" mnemonicParsing="false" onAction="#cancelButtonHandler" prefWidth="130.0" text="%newProject.button.cancel" /> + <Button fx:id="finishButton" defaultButton="true" mnemonicParsing="false" onAction="#finishButtonHandler" prefWidth="130.0" text="%profileChoose.button.finish" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/profileSettingsView.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/profileSettingsView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..f683242929d1be0b9ad6c09795524bf2ba049fee --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/profileSettingsView.fxml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="445.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <ListView fx:id="profileList" layoutX="14.0" layoutY="14.0" prefHeight="376.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <Button fx:id="chooseButton" layoutX="523.0" layoutY="360.0" mnemonicParsing="false" onAction="#chooseButtonHandler" text="%profile.button.choose" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" /> + <VBox layoutX="236.0" layoutY="253.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="214.0"> + <children> + <Button fx:id="newButton" layoutX="236.0" layoutY="253.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#newButtonHandler" text="%profile.button.new" VBox.vgrow="ALWAYS" /> + <Button fx:id="duplicateButton" layoutX="236.0" layoutY="289.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#duplicateButtonHandler" text="%profile.button.duplicate" VBox.vgrow="ALWAYS" /> + <Button fx:id="deleteButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#deleteButtonHandler" text="%profile.button.delete" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + <HBox alignment="CENTER_LEFT" layoutX="214.0" layoutY="17.0" spacing="14.0" AnchorPane.leftAnchor="214.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <Label layoutX="214.0" layoutY="22.0" text="%profile.label.name" /> + <TextField fx:id="nameTextField" layoutX="272.0" layoutY="17.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + <Label alignment="TOP_LEFT" layoutX="214.0" layoutY="82.0" prefHeight="184.0" prefWidth="216.0" text="%profile.label.info" wrapText="true" AnchorPane.bottomAnchor="134.0" AnchorPane.leftAnchor="214.0" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="82.0" /> + <Button fx:id="renameButton" layoutX="347.0" layoutY="48.0" mnemonicParsing="false" onAction="#renameButtonHandler" text="%profile.button.rename" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="48.0" /> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/project/exportDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/exportDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..103db556aa08bc7dd67c6f8474d3e8f6dc82fd02 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/exportDialog.fxml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<StackPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <VBox spacing="14.0"> + <children> + <VBox layoutX="14.0" layoutY="14.0" spacing="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <Label layoutX="14.0" layoutY="14.0" text="%project.export.label.headline" /> + <CheckBox fx:id="profileCheckBox" layoutX="29.0" layoutY="42.0" mnemonicParsing="false" text="%project.export.checkbox.profile" /> + <CheckBox fx:id="mediaCheckBox" layoutX="29.0" layoutY="69.0" mnemonicParsing="false" text="%project.export.checkbox.media" /> + </children> + </VBox> + <HBox alignment="BOTTOM_RIGHT" layoutX="457.0" layoutY="102.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" VBox.vgrow="ALWAYS"> + <children> + <Button fx:id="cancelButton" layoutX="457.0" layoutY="102.0" mnemonicParsing="false" onAction="#cancelButtonHandler" text="%project.export.button.cancel" /> + <Button fx:id="saveButton" layoutX="528.0" layoutY="102.0" mnemonicParsing="false" onAction="#saveButtonHandler" text="%project.export.button.save" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> + </VBox> + </children> +</StackPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/project/openDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/openDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..b0aae277d16ff7e84307867b50aa13b027b8ca8f --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/openDialog.fxml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <AnchorPane fx:id="rootNode" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <children> + <ListView fx:id="projectList" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <VBox layoutX="200.0" prefHeight="200.0" prefWidth="100.0" spacing="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="200.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label text="%project.label.name" /> + <TextField fx:id="nameTextField" HBox.hgrow="ALWAYS" /> + <Button fx:id="renameButton" mnemonicParsing="false" onAction="#renameButtonHandler" text="%project.button.rename" /> + </children> + </HBox> + <Separator prefWidth="200.0" /> + <HBox spacing="14.0"> + <children> + <VBox spacing="14.0"> + <children> + <Label text="%project.label.fileSize" /> + <Label text="%project.label.lastModified" /> + </children> + </VBox> + <VBox spacing="14.0"> + <children> + <Label fx:id="sizeLabel" text="100 MB" /> + <Label fx:id="dateLabel" text="20. Dez 2015 19:45" /> + </children> + </VBox> + </children> + </HBox> + <HBox spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <VBox spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <Button fx:id="newButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#newButtonHandler" text="%project.button.new" VBox.vgrow="ALWAYS" /> + <Button fx:id="duplicateButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#duplicateButtonHandler" text="%project.button.duplicate" VBox.vgrow="ALWAYS" /> + <Button fx:id="deleteButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#deleteButtonHandler" text="%project.button.delete" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + <VBox spacing="14.0"> + <children> + <Button fx:id="exportButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#exportButtonHandler" text="%project.button.export" VBox.vgrow="ALWAYS" /> + <Button fx:id="importButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#importButtonHandler" text="%project.button.import" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + </children> + </HBox> + <Separator prefWidth="200.0" /> + <HBox alignment="TOP_RIGHT" spacing="14.0"> + <children> + <Button fx:id="cancelButton" mnemonicParsing="false" onAction="#cancelButtonHandler" text="%project.button.cancel" /> + <Button fx:id="openButton" mnemonicParsing="false" onAction="#openButtonHandler" text="%project.button.finish" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> + </VBox> + </children> + </AnchorPane> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/dialog/project/printDialog.fxml b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/printDialog.fxml new file mode 100644 index 0000000000000000000000000000000000000000..9e2f0f9c41b401e6ba60d67c7a98996ec011335a --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/dialog/project/printDialog.fxml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import javafx.scene.web.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <WebView fx:id="webView" prefHeight="348.0" prefWidth="600.0" AnchorPane.bottomAnchor="52.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="360.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0"> + <children> + <Label layoutX="14.0" layoutY="365.0" text="%print.label.page" /> + <ComboBox fx:id="pageComboBox" layoutX="94.0" layoutY="360.0" prefWidth="150.0" /> + </children> + </HBox> + <HBox layoutX="463.0" layoutY="360.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0"> + <children> + <Button fx:id="cancelButton" layoutX="463.0" layoutY="360.0" mnemonicParsing="false" onAction="#cancelButtonHandler" text="%print.button.cancel" /> + <Button fx:id="printButton" layoutX="528.0" layoutY="360.0" mnemonicParsing="false" onAction="#printButtonHandler" text="%print.button.print" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/files/Test-Sound.wav b/PlayWall/assets/de/tobias/playpad/assets/files/Test-Sound.wav new file mode 100644 index 0000000000000000000000000000000000000000..1a627d7c84165c6131c47134b1ca1f4fcb0bf3be Binary files /dev/null and b/PlayWall/assets/de/tobias/playpad/assets/files/Test-Sound.wav differ diff --git a/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.png b/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.png new file mode 100644 index 0000000000000000000000000000000000000000..79a1e57c0fabf8751169b46cd0be117ca457adad Binary files /dev/null and b/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.png differ diff --git a/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.pxm b/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.pxm new file mode 100644 index 0000000000000000000000000000000000000000..34238c749b4b88804485d74eb87307a03d2588e6 Binary files /dev/null and b/PlayWall/assets/de/tobias/playpad/assets/files/dialogDnD.pxm differ diff --git a/PlayWall/assets/de/tobias/playpad/assets/lang/_de.properties b/PlayWall/assets/de/tobias/playpad/assets/lang/_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..054e2ce5b5f25c3fd4ee0c2f390d9523d0dd0aa3 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/lang/_de.properties @@ -0,0 +1,224 @@ +# Hier sind Sachen, die dynamisch im Code verwendet werden. Also wenn eine spezielle Aktionen ist. Beispielsweise Fehlermeldung und Hinweise. Die Sachen sind aber trotzdem in der UI. +#Kommentare befinden sich immer -->�BER<-- dem jeweiligen Eintrag + +# Standard - File +Standard.File.Save=Gespeichert +Standard.Copy={} - Kopie +Standard.Time.Seconds={} sec + +# File - Filter +File.Filter.ZIP=Archivedatei +File.Filter.Media=Medien +File.Filter.Preset=Vorlagen + +# Timemode - Enum +Pad.TimeMode.PLAYED=Abgelaufene Zeit +Pad.TimeMode.REST=Verbleibende Zeit +Pad.TimeMode.BOTH=Abgelaufende Zeit / Gesamtzeit + +# UI - Window - Titles +UI.Dialog.Launch.Title=Projekt w�hlen... +UI.Window.Main.Title=Play Wall [Projekt: {} - Profil: {}] +UI.Window.Changelog.Title=Was ist neu? +UI.Window.Settings.Title=Einstellungen - {} +UI.Window.PadSettings.Title=Kachel Einstellungen - {} | {} +UI.Dialog.DragAndDrop.Title=Drag and Drop +UI.Dialog.ProjectExport.Title=Project exportieren +UI.Dialog.ErrorSummary.Title=Fehlerbericht +UI.Dialog.NewProfile.Title=Neues Profil +UI.Dialog.NewProject.Title=Neues Projekt +UI.Dialog.ChooseProfile.Title=Profil w�hlen +UI.Dialog.ProjectManager.Title=Projektverwaltung +UI.Dialog.UpdateCenter.Title=Aktualisierungen +UI.Dialog.Preset.Title=Vorlagen +UI.Dialog.Plugins.Title=Erweiterungen +UI.Dialog.Print.Title=Drucken +UI.Dialog.Profile.Title=Profile + +# UI - Standard +UI.Standard.DoNotShow=Nicht mehr anzeigen + +# UI - Layout - Classic - Theme - Enum +UI.Layout.Classic.Theme.DARK=Dunkel +UI.Layout.Classic.Theme.TWILIGHT=Dunkelblau (Twilight) +UI.Layout.Classic.Theme.LIGHT=Hell + +# UI - Window - Main +UI.Window.Main.CloseRequest=Es wird gerade noch Musik abgespielt. M�chten Sie PlayWall trotzdem beenden? +UI.Window.Main.PageButton = Seite {} + +# UI - Dialog - Launch +UI.Dialog.Launch.Info={} - {} + +# UI Window - Settings +UI.Window.Settings.Gen.Title=Allgemein +UI.Window.Settings.Gen.CacheSize=Gr��e: {}B +UI.Window.Settings.Mapping.Title=Mapping +UI.Window.Settings.Midi.Title=Midi +UI.Window.Settings.Layout.Title=Layout +UI.Window.Settings.Player.Title=Player +UI.Window.Settings.Audio.Title=Audio +UI.Window.Settings.Updates.Title=Updates + +# UI - Dialog - DragAndDrop +UI.Dialog.DragAndDrop.Header=Hinweis +UI.Dialog.DragAndDrop.Content=F�r das Verschieben von Kacheln gibt es zwei M�glichkeiten: Vertauschen oder Ersetzen.\nUm die gw�hlte Kachel mit der Zielkachel zu vertauschen, muss der obere Teil der Zielkachel gew�hlt werden. Es erscheint eine blaue Umrandung. \nUm die ausgew�hlte Kachel mit der Zielkachel zu ersetzen, muss der untere Teil der Zielkachel gew�hlt werden. Es erscheint eine rote Umrandung. +UI.Dialog.DragAndDrop.Button=OK + +# UI - Dialog - NewProfile +UI.Dialog.NewProfile.Content=Geben Sie einen Namen f�r das neue Profil ein: + +# UI - Dialog - NewProject +UI.Dialog.NewProject.Content=Geben Sie einen Namen f�r das neue Projekt ein. + +# UI - Dialog - Import +UI.Dialog.Import.ReplaceProfile.Content=Es gibt bereits eine Profil mit dem Namen {}. Bitte nennen Sie das Profil um. +UI.Dialog.Import.ReplaceProfile.Skip=Import �berspringen +UI.Dialog.Import.ReplaceProfile.Rename=Umbenennen +UI.Dialog.Import.ReplaceProfile.ReplaceContent=Es gibt bereits ein Profil mit dem Namen {}.\nBitte geben Sie einen neuen Namen ein. +UI.Dialog.Import.ReplaceProject.ReplaceContent=Es gibt bereits ein Projekt mit dem Namen {}.\nBitte geben Sie einen neuen Namen ein. +UI.Dialog.Import.ReplaceMedia.Content=M�chten Sie die Mediendaten von diesem Projekt importieren? +UI.Dialog.Import.ReplaceMedia.Copy=Kopieren +UI.Dialog.Import.ReplaceMedia.Skip=�berspringen + +# UI - Dialog - ProjectManager +UI.Dialog.ProjectManager.Delete.Content=M�chten Sie das Projekt {} wirklich l�schen? + +# UI - Dialog - Profile +UI.Dialog.Profile.Delete.Content=Sind Sie sicher, dass Sie das Profil {} l�schen m�chten? + +# UI - Dialog - Info +UI.Dialog.Info.Header=�ber {} +UI.Dialog.Info.Content=Version: {} (Build: {})\nAutor: {}\n\nDieses Programm nutzt Bibliotheken. ControlsFX (8.40.10), dom4j (1.6.1), snakeyaml (1.11), guava (15.0), gagawa (1.0.1), TinySound (1.1.1), JLayer (1.0.1), JSPF (1.0.2), json-smart (1.2). \nBesonderen Dank an die Betatester: Stefan, Robert. + +# UI - Dialog - Feedback +UI.Dialog.Feedback.Content=Der Fehlerbericht wird �bermittelt. Bitte haben Sie etwas Geduld. Ihre Nummer wird am Ende angezeigt. + +# UI - Placeholder +UI.Placeholder.Project=Keine Projekte vorhanden +UI.Placeholder.Preset=Keine Vorlagen vorhanden +UI.Placeholder.Plugins=Keine Plugins vorhanden +UI.Placeholder.Updates=Es sind keine Updates verf�gbar +UI.Placeholder.ErrorSummary=Keine Fehler + +# Info - MIDI +Info.Midi.Device.Connected=Midi Ger�t erkannt ({}) + +# Info - Settings +Info.Settings.ResetWarning=Die Einstellungen wurden zur�ckgesetzt. +Info.Settings.CacheDelete={} Dateien wurden gel�scht. + +# Info - Print +Info.Print.Header={} - Seite {} + +# Error - Standard +Error.Standard.Gen=Es ist ein Fehler aufgetreten, bitte versuchen Sie es sp�ter noch einmal. ({}) +Error.Standard.NameInUse=Der Name {} kann nicht gew�hlt werden, da er bereits vergeben ist. + +# Error - Settings +Error.Settings.CacheSize=Die Gr��e des Cache kann nicht bestimmt werden. ({}) +Error.Settings.CacheClear=Beim L�schen des Caches ist ein Fehler aufgetreten. ({}) + +# Error - Profile +Error.Profile.Create=Das Profil konnte aufgrund eines Fehlers nicht erstellt werden. ({}) +Error.Profile.NotFound=Das Profil konnte nicht geladen werden, da die Datein fehlen. W�hle eine neues Profile und �ffne das Projekt erneut. ({}) +Error.Profile.Save=Das Profil konnte aufgrund eines Fehlers nicht gespeichert werden. ({}) +Error.Profile.Delete=Das Projekt konnte nicht gel�scht werden. ({}) +Error.Profile.SmallScreen=Ihr Bildschirm ist f�r die gew�hlte Anzahl der Kacheln zu klein. (Maximal: {}x{}) + +# Error - Preset +Error.Preset.Import=Es ist ein Fehler beim Importieren der Vorlage aufgetreten. ({}) +Error.Preset.Export=Die Vorlage konnte nicht exportiert werden. ({}) + +# Error - Project +Error.Project.Create=Das Projekt konnte nicht erstellt werden. ({}) +Error.Profile.NotFound=Das Projekt {} konnte nicht ge�ffnet werden, da die Projektdatei nicht gefunden wurde. ({}) +Error.Project.Open=Das Projekt {} konnte nicht ge�ffnet werden. ({}) +Error.Project.Save=Das Projekt {} konnte nicht gespeichert werden. ({}) +Error.Project.Rename=Das Projekt konnte nicht umbenannt werden. ({}) +Error.Project.Delete=Das Projekt konnte nicht gel�scht werden. ({}) +Error.Project.Export=Das Projekt {} konnte nicht exportiert werden. ({}) + +# Error - Pad - Enum +Error.Pad.FILE_NOT_FOUND=Die Datei {} konnte nicht gefunden werden. +Error.Pad.FILE_FORMAT_NOT_SUPPORTED=Die Datei {} ist inkompatibel. +Error.Pad.CONVERT_NOT_SUPPORTED=Die Datei {} kann nicht umgewandelt werden. (W�hlen Sie ein anderes Format zum Import aus) +Error.Pad.UNKOWN=Es ist ein Unbekannter Fehler aufgetreten. {} +Error.Pad.UNKOWN_CONTENT_TYPE=Die Kachel {} konnte nicht geladen werden. + +# Error - L�sung +Error.Fix.NewFile=Neue Datei w�hlen + +# Error - Midi +Error.Midi.Settings.Unkown=F�r die ausgew�hlte Seite sind keine Midi Einstellungen aktiv. In Einstellungen -> Midi -> Presets kann dies angepasst werden. +Error.Midi.Device.Busy=Das Midi-Ger�t wird bereits durch ein anderes Programm verwendet. ({}) +Error.Midi.Device.Unavailible=Das Midi-Ger�t {} konnte nicht gefunden werden. +Error.Midi.Record.Fail=Die gedr�ckte Taste wird bereits verwendet. +Error.Midi.Send=Der Midi Befehl konnte nicht gesendet werden. ({}) + +# Error - Plugins +Error.Plugins.Download=Das Plugin {} konnte nicht geladen werden. + +#Mapper +Mapper.Keyboard.Name=Tastatur +Mapper.Midi.Name=Midi +Mapper.Keyboard.toString=Tastatur {} +Mapper.Midi.toString=Midi {} + +# Info - Mapper +Info.Mapper.PressKey=Dr�cken Sie eine Taste auf dem Ger�t. + +# UI - Window - PadSettings +UI.Window.PadSettings.General.Title=Allgemein +UI.Window.PadSettings.Player.Title=Player +UI.Window.PadSettings.Layout.Title=Layout +UI.Window.PadSettings.Trigger.Title=Trigger + +# Actions +Action.Cart.toString=Kachel {} +Action.Page.toString=Seite {} +Action.Navigate.toString={} +Action.Cart.Name=Kacheln +Action.Page.Name=Seiten +Action.Navigate.Name=Navigation + +#Content +Content.Empyt=Leer +Content.Audio.Name=Audio + +# NavigationType - Enum +NavigationType.PREVIOUS=Vorherige Seite +NavigationType.NEXT=N�chste Seite + +# CartAction - Enum +CartAction.Mode.PLAY_STOP=Play/Stop +CartAction.Mode.PLAY_PAUSE=Play/Pause +CartAction.Mode.PLAY_HOLD=Play/Hold + +#UI - Dialog -AutoUpdate +UI.Dialog.AutoUpdate.Header=Updates +UI.Dialog.AutoUpdate.Content=Es gibt Updates. Weitere Informationen finden Sie in den Update Einstellungen. Wollen Sie die Updates jetzt installieren? + +# Error - Layout +Error.Layout.Load=Es gab einen Fehler beim Laden des Layouts ({}) + +# UI - Dialog - Update +UI.Dialog.Update.Cell={}: Installiert: {} - Neu: {} +UI.Window.Settings.Updates.CurrentVersion={} (Build {}) +UI.Window.Settings.Updates.NewVersion={} (Build {}) + +# Error - Update - Downlaod +Error.Update.Download=Es ist ein Fehler beim Downloaden des Updates aufgetreten. Bitte versuchen Sie es sp�ter noch einmal. ({}) + +# Layout +Layout.Modern.Name=Modern +Layout.Classic.Name=Klassisch + +# Trigger +TriggerPoint.toString={} ({}) +Trigger.Cart.Name=Kacheln +Trigger.Volume.Name=Lautst�rke + +# TriggerPoint - Enum +TriggerPoint.START=Start +TriggerPoint.EOF_STOP=Ende/Stop \ No newline at end of file diff --git a/PlayWall/assets/de/tobias/playpad/assets/lang/ui_de.properties b/PlayWall/assets/de/tobias/playpad/assets/lang/ui_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..ae2924f4608d192e0c581a1b3e39abf905ed8773 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/lang/ui_de.properties @@ -0,0 +1,196 @@ +#Sprachdatei f�r die Benutzeroberfl�che + +main.menu.file=Datei +main.menu.option=Optionen +main.menu.view=Ansicht +main.menu.info=Info +main.menu.extension=Erweitert + +main.menuitem.new=Neues Projekt... +main.menuitem.project=Projekte verwalten... +main.menuitem.save=Projekt speichern... +main.menuitem.recentFiles=Zuletzt verwendete Projekte +main.menuitem.profile=Profile verwalten... +main.menuitem.print=Drucken... +main.menuitem.onTop=Fenster im Vordergrund +main.menuitem.plugins=Erweiterungen... +main.menuitem.dnd=Bearbeitungsmodus +main.menuitem.errors=Fehlerbericht anzeigen... +main.menuitem.settings=Einstellungen... +main.menuitem.about=�ber Play Wall... +main.menuitem.website=Webseite besuchen... +main.menuitem.senderror=Fehler senden... +main.menuitem.fullScreen=Vollbild + +main.label.live=Live + +settings.gen.label.view=Ansicht: +settings.gen.label.pages=Anzahl der Seiten: +settings.gen.label.columns=Anzahl der Spalten: +settings.gen.label.rows=Anzahl der Reihen: +settings.gen.label.additional=Erweitert: +settings.gen.label.liveMode=Live Modus: +settings.gen.checkbox.liveMode=Aktivieren +settings.gen.label.liveModeInfo=Der Live Modus verhindet ungewollte Aktionen w�hrend der Wiedergabe einer Kachel. +settings.gen.warning.button.reset=Hinweismeldungen zur�cksetzen +settings.gen.cache.label=Cachespeicher: +settings.gen.cache.button.choose=W�hlen +settings.gen.cache.button.reset=Cache leeren +settings.gen.cache.label.info=Wenn Sie als Audioausgabetyp "Java Audiostream" gew�hlt haben, werden jegliche MP3-Dateien in eine WAV-Dateien umgewandelt. Diese wird dann in den oben angegebenen Ordner abgelegt. Sollen Sie viele Dateien aus Ihrem Projekt gel�scht haben, ist es sinnvoll, den Cache zu leeren, um die ben�tigten Speicher zu verringern. Ben�tigte Dateien werden automatisch neu umgewandelt, falls sie nicht (mehr) existieren. + +settings.mapping.label.mapping=Mapping: +settings.mapping.button.edit=Bearbeiten... + +settings.midi.button.activate=Aktivieren +settings.midi.label.device=Midi Ger�te: + +settings.layout.label.type=Layout Type: + +settings.player.label.warning=Warnhinweise: +settings.player.label.fade=Ein-/Ausblenden: +settings.player.label.fadeIn=Einblenden (in s): +settings.player.label.fadeOut=Ausblenden (in s): +settings.player.label.startIn=... nach Start +settings.player.label.pauseIn=... nach Pause +settings.player.label.pauseOut=... vor Pause +settings.player.label.stopOut=... vor Stop (nicht Ende) +settings.player.label.fadeInfo=Wird beim Ein- oder Ausblenden die Dauer auf 0 gesetzt, so findet keine �berblendung statt. Wenn der Sound zu Ende ist, findet kein Ausblenden statt. +settings.player.label.timeDisplay=Zeitanzeige: + +settings.update.label.current=Installierte Version: +settings.update.label.new=Aktuelle Version: +settings.update.label.search=Nach updates suchen: +settings.update.label.available=Verf�gbare Updates: +settings.update.button.search=Jetzt suchen +settings.update.button.install=Aktualisieren und neu starten + +settings.button.finish=Fertig +settings.checkbox.activate=Aktivieren + +layout.label.programmLayout=Programmlayout: +layout.label.customLayout=Eigenes Layout: +layout.label.baseColor=Akzentfarbe: +layout.label.background=Hintergrund: +layout.label.playground=Hintergrund w�hrend Wiedergabe: +layout.label.fadeColor=Hintergrund w�hrend Ausblenden: +layout.label.warnColor=Warnhinweis: +layout.label.color=Farbe: +layout.label.fontSize=Schriftgr��e: +layout.label.infoLabel=Kopfzeile: +layout.label.titleLabel=Titel: +layout.label.animation=Animationen: +layout.label.warnAnimation=Warnhinweise +layout.button.reset=Zur�cksetzen + +midi.label.key=Taste (Midi): +midi.button.new=�ndern + +keyboard.label.key=Taste (Tastatur): +keyboard.button.new=�ndern + +padSettings.button.delete=L�schen + +padSettings.gen.label.title=Titel: +padSettings.gen.label.volume=Lautst�rke: +padSettings.gen.label.timeDisplay=Zeitanzeige: +padSettings.gen.checkbox.customSettings=Eigene Einstellungen +padSettings.checkbox.loop=Wiederholen +padSettings.button.finish=Fertig + +padSettings.player.label.warning=Warnhinweise: +padSettings.player.label.fade=Ein-/Ausblenden: + +padSettings.layout.label.custom=Eigenes Layout: +padSettings.layout.checkbox.custom=aktiviert + +project.button.finish=�ffnen +project.button.cancel=Abbrechen +project.button.delete=L�schen +project.button.rename=Umbenennen +project.button.new=Neues Projekt +project.button.duplicate=Duplizieren +project.button.export=Exportieren... +project.button.import=Importieren.. +project.label.name=Name: +project.label.fileSize=Dateigr��e +project.label.lastModified=Zuletzt bearbeitet: + +project.export.label.headline=Projekt exportieren: +project.export.checkbox.profile=Zus�tzlich das Profil mit exportieren? +project.export.checkbox.media=Zus�tzlich die Medieninhalte exportieren? +project.export.button.cancel=Abbrechen +project.export.button.save=Speichern... +#Project import ist in der _de.properties + +launch.button.import=Projekt importieren +launch.button.new=Neues Projekt +launch.button.open=�ffnen +launch.button.delete=L�schen + +profile.label.name=Name +profile.label.info=Ein Profil umfasst alle Einstellungen des Programmes, beispielsweise das Aussehen, die Midi-Einstellungen oder die Audioeinstellungen. Sie k�nnen jederzeit f�r ein Projekt das Profil wechseln. +profile.button.rename=Umbenennen +profile.button.new=Neu +profile.button.delete=L�schen +profile.button.duplicate=Duplizieren +profile.button.choose=Profil w�hlen + +warning.label.time=Warnhinweis ab Restdauer: (Sek) + +print.label.page=Seite: +print.button.cancel=Abbrechen +print.button.print=Drucken + +plugin.label.restart=Einige �nderungen werden erst nach dem Neustart des Programmes wirksam. +plugin.label.updateInfo=Plugins k�nnen in den Updateeinstellungen aktualisiert werden. +plugin.button.finish=Fertig + +settings.audio.type=Ausgabe Type w�hlen: + +newProject.label.name=Name: +newProject.label.profile=Profil: +newProject.button.newProfile=Neues Profil... +newProject.button.finish=Projekt erstellen +newProject.button.cancel=Abbrechen + +newProfile.label.name=Name: +newProfile.label.midiSettings=Midi Einstellungen: +newProfile.label.midi=Midi Funktion: +newProfile.button.finish=Profil erstellen +newProfile.button.cancel=Abbrechen + +profileChoose.label.info=Die Voreinstellungen zu diesem Projekt wurden nicht gefunden.\nBitte w�hlen Sie neue Voreinstellungen aus. +profileChoose.button.finish=Profil w�hlen + +doubleFeedback.label.colorEvent=Event Farbe: +doubleFeedback.label.colorDefault=Standard Farbe: + +cartAction.label.headline=Einstellungen zur Kachel: +cartAction.label.type=Typ: +cartAction.label.autoColor=Feedback wie Layout: +cartAction.checkbox.autoColor=Aktivieren + +action.mapper.headline=Einstellungen zum Mapping: + +mappingPreset.button.add=Hinzuf�gen +mappingPreset.button.duplicate=Duplizieren +mappingPreset.button.export=Exportieren... +mappingPreset.button.import=Importieren... +mappingPreset.button.delete=L�schen +mappingPreset.button.finish=Fertig +mappingPreset.label.mapping=Mapping: +mappingPreset.label.name: Name: + +errorSummary.label.headline=Fehlerzusammenfassung: +errorSummary.column.cart=Kachel +errorSummary.column.des=Fehlerbeschreibung +errorSummary.column.solution=L�sung +errorSummary.button.close=Schlie�en + +tinysound.label.soundcard=Sound Karte: + +triggertime.label.time=Zeit vom Trigger: (Sek) + +carttrigger.label.action=Aktion f�r Kacheln: +carttrigger.label.carts=Kacheln: +carttrigger.checkbox.all=Alle (au�er diese) diff --git a/PlayWall/assets/de/tobias/playpad/assets/modern_style.css b/PlayWall/assets/de/tobias/playpad/assets/modern_style.css new file mode 100644 index 0000000000000000000000000000000000000000..8c1ff6afa671324e61247d11ffb1072ad84891d0 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/modern_style.css @@ -0,0 +1,134 @@ +.root { + -fx-base: rgb(30, 30, 30); +} + +.deleteButton { + -fx-background-color: transparent; + -fx-padding: 0; +} + +.pad:drag { + -fx-opacity: 0.8; +} + +.text-field:error { + -fx-text-box-border: red; + -fx-focus-color: red; +} + +.live-label { + -fx-text-fill: red !important; +} + +// Neu +.pad { + /* + -fx-background-color: linear-gradient(#A7FF9A, #8FD673); // Grün + -fx-background-color: linear-gradient(#469fe2, #0080e2); // Blau + + + -fx-background-color: linear-gradient(#a90329, #6d0019); // Weinrot F + -fx-background-color: linear-gradient(#55B7FF, #369FE9); // Blau F + -fx-background-color: linear-gradient(#FF6E6B, #EF5350); // Rot F + -fx-background-color: linear-gradient(#73E178, #66BB6A); // Grün F + -fx-background-color: linear-gradient(#ffe08c, #d5bf54); // Gelb F + -fx-background-color: linear-gradient(#db7ab7, #dd61b0); // Pink F + -fx-background-color: linear-gradient(#ff9254, #ff7526); // Orange F + -fx-background-color: linear-gradient(#86F7FF, #52E3EC); // Aqua F + -fx-background-color: linear-gradient(#555555, #333333); // Dark F + -fx-background-color: linear-gradient(#eeeeee, #cccccc); // Grau F + -fx-background-color: linear-gradient(#cccccc, #aaaaaa); // Mittel Grau F + */ + + -fx-background-radius: 10px; + + -fx-border-color: rgb(20, 20, 20); + -fx-border-width: 2px; + -fx-border-radius: 8px; + + -fx-padding: 5 10 5 10; +} + +.pad-root { + -fx-spacing: 4px; +} + +.pad-button-box { + -fx-spacing: 0px; +} + +.pad-grid { + -fx-background-color: rgb(60, 60, 60); + + -fx-hgap: 6px; + -fx-vgap: 6px; + + -fx-padding: 6px; +} + +.pad-info { + -fx-text-fill: white; + -fx-font-size: 15px; +} + +.pad-button { + -fx-background-color: transparent; + -fx-border-color: transparent; +} + + +.pad-button:hover { + -fx-background-color: transparent; + -fx-border-width: 1px; + -fx-border-color: rgb(30, 30, 30, 0.5); + -fx-border-radius: 10px; +} + +.pad-button:pressed { + -fx-background-color: transparent; + -fx-border-width: 1px; + -fx-border-color: black; + -fx-border-radius: 10px; +} + +.fonticon { + -fx-text-fill: white; + -fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.5), 4, 0.1, 1, 1); +} + +.pad-playbar .bar { + -fx-background-color: white; + -fx-padding: 0.5em; + + -fx-background-radius: 10px; +} + +.pad-playbar .track { + -fx-base: black; + -fx-background-radius: 10px; +} + +.pad-playbar { + -fx-background-radius: 10px; + -fx-effect: dropshadow( gaussian , rgba(0, 0, 0, 0.5), 8, 0.5, 2, 2); +} + +.tool-bar { + -fx-base: rgb(60, 60, 60); +} + +.menu-bar { + -fx-base: rgb(60, 60, 60); +} + +.current-page-button { + -fx-base: lightgray; +} + +.slider .thumb { + -fx-base: white; +} + +.volume-item { + -fx-text-fill: white !important; +} diff --git a/PlayWall/assets/de/tobias/playpad/assets/settings/fadeView.fxml b/PlayWall/assets/de/tobias/playpad/assets/settings/fadeView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..d736fbbff8080e0e0fd31ea92b900d0adbfe19a7 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/settings/fadeView.fxml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox prefWidth="500.0" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="19.0" prefWidth="150.0" text="%settings.player.label.fadeIn" textAlignment="RIGHT" /> + <VBox spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <HBox spacing="14.0"> + <children> + <Slider fx:id="fadeInSlider" blockIncrement="0.1" majorTickUnit="1.0" max="10.0" maxWidth="1.7976931348623157E308" minorTickCount="9" showTickLabels="true" showTickMarks="true" snapToTicks="true" HBox.hgrow="ALWAYS" /> + <Label fx:id="fadeInLabel" prefWidth="75.0" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <CheckBox fx:id="fadeInStartCheckBox" mnemonicParsing="false" text="%settings.player.label.startIn" /> + <CheckBox fx:id="fadeInPauseCheckBox" mnemonicParsing="false" text="%settings.player.label.pauseIn" /> + </children> + </HBox> + </children> + </VBox> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="53.0" prefWidth="150.0" text="%settings.player.label.fadeOut" textAlignment="RIGHT" /> + <VBox spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <HBox spacing="14.0"> + <children> + <Slider fx:id="fadeOutSlider" blockIncrement="0.1" majorTickUnit="1.0" max="10.0" maxWidth="1.7976931348623157E308" minorTickCount="9" showTickLabels="true" showTickMarks="true" snapToTicks="true" HBox.hgrow="ALWAYS" /> + <Label fx:id="fadeOutLabel" prefWidth="75.0" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <CheckBox fx:id="fadeOutPauseCheckBox" mnemonicParsing="false" text="%settings.player.label.pauseOut" /> + <CheckBox fx:id="fadeOutStopCheckBox" mnemonicParsing="false" text="%settings.player.label.stopOut" /> + </children> + </HBox> + </children> + </VBox> + </children> + </HBox> + <Label maxWidth="1.7976931348623157E308" text="%settings.player.label.fadeInfo" wrapText="true" VBox.vgrow="ALWAYS"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Label> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/settings/warningFeedbackSettingsView.fxml b/PlayWall/assets/de/tobias/playpad/assets/settings/warningFeedbackSettingsView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..c203846c01b6c92c94bba75699eb7b9618ba64c4 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/settings/warningFeedbackSettingsView.fxml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.shape.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="14.0" prefWidth="150.0" text="%warning.label.time" textAlignment="RIGHT" wrapText="true" AnchorPane.leftAnchor="14.0" /> + <Slider fx:id="warningFeedbackTimeSlider" blockIncrement="0.1" majorTickUnit="1.0" max="10.0" minorTickCount="9" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="5.0" HBox.hgrow="ALWAYS" /> + <Label fx:id="warningFeedbackTimeLabel" prefWidth="75.0" /> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/style.css b/PlayWall/assets/de/tobias/playpad/assets/style.css new file mode 100644 index 0000000000000000000000000000000000000000..40d94559897cdc6ca42596283df2053edf65483a --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/style.css @@ -0,0 +1,30 @@ +.text-field:error { + -fx-text-box-border: red ; + -fx-focus-color: red ; +} + +.color-view-item { + -fx-stroke: black; + -fx-stroke-width: 2; + -fx-arc-height: 7.5; + -fx-arc-width: 7.5; +} + +.color-view-item:hover { + -fx-stroke: DARKRED; +} + +.color-view-item:pressed { + -fx-stroke: RED; +} + +.dnd-file-option { + -fx-text-fill: white; +} + +.dnd-file-option:drag { + -fx-text-fill: white; + -fx-border-width: 2px; + -fx-border-color: white; + -fx-border-radius:10px; +} diff --git a/PlayWall/assets/de/tobias/playpad/assets/style/Dark.css b/PlayWall/assets/de/tobias/playpad/assets/style/Dark.css new file mode 100644 index 0000000000000000000000000000000000000000..b169cecdab23acef41f7350f255a0a346e46c1e0 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/style/Dark.css @@ -0,0 +1,95 @@ +.root { + -fx-base: rgb(40, 40, 40); + -fx-background: rgb(40, 40, 40); + -fx-control-inner-background: rgb(45, 45, 45); +} + +.tab { + -fx-background-color: linear-gradient(to top, -fx-base, derive(-fx-base,50%)); +} + +.tab:selected { + -fx-background-color: linear-gradient(to bottom, -fx-base, derive(-fx-base,50%)); +} + +.menu-bar { + -fx-background-color: linear-gradient(to bottom, -fx-base, derive(-fx-base, 15%)); +} + +.menu:hover, +.menu-item:hover, +.menu:showing, +.menu-item:focused, +.list-view .list-cell:selected, +.combo-box-popup .list-view .list-cell:filled:selected, +.combo-box-popup .list-view .list-cell:filled:selected:hover, +.combo-box-popup .list-view .list-cell:filled:hover { + -fx-background-color: rgb(70, 70, 70); + -fx-text-fill: white; +} + +.tool-bar:horizontal { + -fx-background-color: linear-gradient(to bottom, derive(-fx-base,+20%), derive(-fx-base,+0%)); + -fx-border: 1px 0px 1px 0px; + -fx-border-color: black; +} + +.button { + -fx-base: black; +} + +.button:hover { + -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; + -fx-color: -fx-hover-base; +} + +.table-view { + -fx-table-cell-border-color:derive(-fx-base,+10%); + -fx-table-header-border-color:derive(-fx-base,+20%); +} + +.fonticon { + -fx-text-fill: red; +} + +.label { + -fx-text-fill: white; + -fx-fill: white; +} + +.pad-playbar { + -fx-accent: #ff0000ff; +} + +.pad:play { + -fx-background-color: #aa5555bb; +} +.pad:warn { + -fx-background-color: #cc0000bb; +} +.pad:fade { + -fx-background-color: #99bb88bb; +} + +.current-page-button { + -fx-base: lightgray; +} + +/*Notification Bar*/ +.notification-pane.dark .notification-bar > .pane { + -fx-background-color: linear-gradient(#D6D6D6, #CCCCCC 37%, #ABABAB); + -fx-padding: 0 7 0 7; +} + +.notification-pane.top .notification-bar > .pane { + -fx-background-insets: 0 0 0 0, 0 0 1 0, 0 0 2 0; +} + +.notification-pane.bottom .notification-bar > .pane { + -fx-background-insets: 0 0 0 0, 1 0 0 0, 2 0 0 0; +} + +.notification-pane .notification-bar > .pane .label { + -fx-font-size: 1.166667em; /*15px;*/ + -fx-text-fill: #292929; +} diff --git a/PlayWall/assets/de/tobias/playpad/assets/style/Light.css b/PlayWall/assets/de/tobias/playpad/assets/style/Light.css new file mode 100644 index 0000000000000000000000000000000000000000..6f0efc0bdbdeccbdf92a148a74d87b100f989b4a --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/style/Light.css @@ -0,0 +1,71 @@ +.root { + /*-fx-base: rgb(40, 40, 40);*/ + /*-fx-background: rgb(40, 40, 40);*/ + /*-fx-control-inner-background: rgb(45, 45, 45);*/ +} + +.menu-bar { + -fx-background-color: linear-gradient(to bottom, -fx-base, derive(-fx-base, 15%)); +} + +.menu:hover, +.menu-item:hover, +.menu:showing, +.menu-item:focused, +.list-view .list-cell:selected, +.combo-box-popup .list-view .list-cell:filled:selected, +.combo-box-popup .list-view .list-cell:filled:selected:hover, +.combo-box-popup .list-view .list-cell:filled:hover { + -fx-background-color: rgb(200, 200, 200); + -fx-text-fill: white; +} + +.tool-bar:horizontal { + -fx-border: 1px 0px 1px 0px; + -fx-border-color: black; +} + +.button:hover { + -fx-color: -fx-hover-base; +} + +.table-view { + -fx-table-cell-border-color:derive(-fx-base,+10%); + -fx-table-header-border-color:derive(-fx-base,+20%); +} + +.split-pane:horizontal > * > .split-pane-divider { + -fx-border-color: transparent -fx-base transparent -fx-base; + -fx-background-color: transparent, derive(-fx-base,20%); + -fx-background-insets: 0, 0 1 0 1; +} + +.fonticon { + -fx-text-fill: black; +} + +.label { + -fx-text-fill: black; +} + +.progress-bar { + -fx-accent: black; +} + +.notification-pane.dark .notification-bar > .pane .label { + -fx-text-fill: #ebebeb; +} + +.pad:play { + -fx-background-color: #aa5555bb; +} +.pad:warn { + -fx-background-color: #cc0000bb; +} +.pad:fade { + -fx-background-color: #ff9933bb; +} + +.current-page-button { + -fx-base: lightgray; +} diff --git a/PlayWall/assets/de/tobias/playpad/assets/style/Twilight.css b/PlayWall/assets/de/tobias/playpad/assets/style/Twilight.css new file mode 100644 index 0000000000000000000000000000000000000000..bdc0554fce821d7b3f1489ed887b47f369ef239a --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/style/Twilight.css @@ -0,0 +1,96 @@ +.root { + -fx-base: rgb(40, 40, 50); + -fx-background: rgb(40, 40, 50); + -fx-control-inner-background: rgb(40, 40, 50); +} + +.tab { + -fx-background-color: linear-gradient(to top, -fx-base, derive(-fx-base,30%)); +} + +.tab:selected { + -fx-background-color: linear-gradient(to bottom, -fx-base, derive(-fx-base,30%)); +} + +.menu-bar { + -fx-background-color: linear-gradient(to top, -fx-base, derive(-fx-base,30%)); +} + +.menu:hover, +.menu-item:hover, +.menu:showing, +.menu-item:focused, +.list-view .list-cell:selected, +.combo-box-popup .list-view .list-cell:filled:selected, +.combo-box-popup .list-view .list-cell:filled:selected:hover, +.combo-box-popup .list-view .list-cell:filled:hover{ + -fx-background-color: rgb(70, 70, 90); + -fx-text-fill: white; +} + +.tool-bar:horizontal { + -fx-background-color: linear-gradient(to bottom, derive(-fx-base,+20%), derive(-fx-base,+0%)); +} + +.button { + -fx-base: rgb(20, 20, 30); +} + +.button:hover { + -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; + -fx-color: -fx-hover-base; +} + +.table-view { + -fx-table-cell-border-color:derive(-fx-base,+10%); + -fx-table-header-border-color:derive(-fx-base,+20%); +} + + +.fonticon { + -fx-text-fill: white; +} + +.label { + -fx-text-fill: white; + -fx-fill: white; +} + +.pad-playbar { + -fx-accent: white; +} + +.pad:play { + -fx-background-color: #aa5555bb; +} + +.pad:warn { + -fx-background-color: #cc0000bb; +} + +.pad:fade { + -fx-background-color: #999988bb; +} + +.current-page-button { + -fx-base: lightgray; +} + +/*Notification Bar*/ +.notification-pane.dark .notification-bar > .pane { + -fx-background-color: linear-gradient(#D6D6D6, #CCCCCC 37%, #ABABAB); + -fx-padding: 0 7 0 7; +} + +.notification-pane.top .notification-bar > .pane { + -fx-background-insets: 0 0 0 0, 0 0 1 0, 0 0 2 0; +} + +.notification-pane.bottom .notification-bar > .pane { + -fx-background-insets: 0 0 0 0, 1 0 0 0, 2 0 0 0; +} + +.notification-pane .notification-bar > .pane .label { + -fx-font-size: 1.166667em; /*15px;*/ + -fx-text-fill: #292929; +} diff --git a/PlayWall/assets/de/tobias/playpad/assets/style/launchDialog_style.css b/PlayWall/assets/de/tobias/playpad/assets/style/launchDialog_style.css new file mode 100644 index 0000000000000000000000000000000000000000..5140429aa49a7b813a470a5d749b29b6df9d8810 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/style/launchDialog_style.css @@ -0,0 +1,72 @@ +/*projectList */ +#list .list-cell { + -fx-skin: "com.sun.javafx.scene.control.skin.ListCellSkin"; + -fx-background-color: -fx-base; + -fx-padding: 10px; + -fx-text-fill: -fx-text-inner-color; + -fx-opacity: 1; +} + +#list .list-cell:filled { + /*-fx-background-color: derive(-fx-control-inner-background,-5%);*/ + -fx-border-width: 0px 0px 1px 0px; + -fx-border-color: #00000044; +} + +#list .list-view:focused .list-cell:focused { + -fx-background-color: derive(-fx-hover-base,+50%); + -fx-background-insets: 0, 1, 2; +} + +#list .list-view:focused .list-cell:focused:odd { + -fx-background-color: derive(-fx-hover-base,+50%); + -fx-background-insets: 0, 1, 2; +} + +/* When the list-cell is selected and focused */ +#list .list-view:focused .list-cell:filled:focused:selected { + -fx-background-color: derive(-fx-hover-base,+50%); + -fx-background-insets: 0, 1, 2; + -fx-background: -fx-base; + -fx-text-fill: -fx-selection-bar-text; +} + +#list .list-view:focused .list-cell:filled:selected, #list .list-view:focused .list-cell:filled:selected:hover { + -fx-background: -fx-base; + -fx-background-color: derive(-fx-hover-base,+50%); + -fx-text-fill: -fx-selection-bar-text; +} + +#list .list-view:focused .list-cell:filled:focused:selected:hover { + -fx-background: -fx-base; + -fx-background-color: derive(-fx-hover-base,+50%); + -fx-background-insets: 0, 1, 2; + -fx-text-fill: -fx-selection-bar-text; +} + +/* When the ListView is _not_ focused, we show alternate selection colors */ +#list .list-cell:filled:selected:focused, #list .list-cell:filled:selected, .list-view:horizontal .list-cell:filled:selected { + -fx-background-color: lightgray; + -fx-text-fill: -fx-selection-bar-text; +} + +#list .list-cell:filled:selected:focused:disabled, #list .list-cell:filled:selected:disabled { + -fx-opacity: -fx-disabled-opacity; +} + +#list .list-cell:filled:hover { + -fx-background-color: -fx-hover-base; + -fx-text-fill: -fx-text-inner-color; +} + +#list .list-view:focused .list-cell:filled:focused:hover { + -fx-background-color: derive(-fx-hover-base,+50%); + + -fx-background-insets: 0, 1, 2; + -fx-text-fill: -fx-text-inner-color; +} + +#list .list-view:horizontal .list-cell:filled:selected, #list .list-view:horizontal .list-cell:filled:selected:hover { + -fx-background-color: derive(-fx-hover-base,+50%); +} + diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartAction.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartAction.fxml new file mode 100644 index 0000000000000000000000000000000000000000..249047f8ba33c886d0fc46d1ca88d9fc76d2a1bc --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartAction.fxml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox fx:id="rootContainer" maxWidth="1.7976931348623157E308" spacing="14.0" VBox.vgrow="ALWAYS" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label text="%cartAction.label.headline" underline="true" /> + <VBox fx:id="settingsView"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="150.0" text="%cartAction.label.type" /> + <ComboBox fx:id="controlMode" prefWidth="150.0" /> + </children> + </HBox> + </children> + </VBox> + <VBox fx:id="settingsView1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" minWidth="150.0" text="%cartAction.label.autoColor" /> + <CheckBox fx:id="autoColorCheckbox" mnemonicParsing="false" text="%cartAction.checkbox.autoColor" /> + </children> + </HBox> + </children> + </VBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartActions.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartActions.fxml new file mode 100644 index 0000000000000000000000000000000000000000..f51a447b46c39cce3eed03f403278af7ff0e9b40 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/actions/cartActions.fxml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + + +<VBox fx:id="buttonVbox" spacing="7.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox fx:id="pageHbox" minHeight="20.0" spacing="7.0" VBox.vgrow="NEVER" /> + <GridPane fx:id="gridPane" alignment="CENTER" hgap="7.0" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" vgap="7.0" VBox.vgrow="NEVER"> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + </rowConstraints> + <VBox.margin> + <Insets /> + </VBox.margin> + </GridPane> + <Separator prefWidth="200.0" /> + <VBox fx:id="cartActionContainer" minHeight="20.0" /> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/audio/clipSettings.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/audio/clipSettings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..dec8adcf9d311f4a8d8c9ab7b27f9fe00a685994 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/audio/clipSettings.fxml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + + +<HBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="19.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%tinysound.label.soundcard" /> + <ComboBox fx:id="soundCardComboBox" layoutX="118.0" layoutY="14.0" prefHeight="26.0" prefWidth="241.0" /> + <Button fx:id="testButton" layoutX="372.0" layoutY="14.0" mnemonicParsing="false" onAction="#testButtonHandler" /> + </children> +</HBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/audio/tinySoundSettings.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/audio/tinySoundSettings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..dec8adcf9d311f4a8d8c9ab7b27f9fe00a685994 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/audio/tinySoundSettings.fxml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + + +<HBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="19.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%tinysound.label.soundcard" /> + <ComboBox fx:id="soundCardComboBox" layoutX="118.0" layoutY="14.0" prefHeight="26.0" prefWidth="241.0" /> + <Button fx:id="testButton" layoutX="372.0" layoutY="14.0" mnemonicParsing="false" onAction="#testButtonHandler" /> + </children> +</HBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/main/mainMenu.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainMenu.fxml new file mode 100644 index 0000000000000000000000000000000000000000..65407383ec6125fd235602d2e35b4814394689fd --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainMenu.fxml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.input.*?> + +<MenuBar fx:id="menuBar" prefHeight="29.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.tobias.playpad.viewcontroller.main.MainMenuBarController"> + <menus> + <Menu mnemonicParsing="false" text="%main.menu.file"> + <items> + <MenuItem mnemonicParsing="false" onAction="#newDocumentHandler" text="%main.menuitem.new"> + <accelerator> + <KeyCodeCombination alt="UP" code="N" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#openDocumentHandler" text="%main.menuitem.project"> + <accelerator> + <KeyCodeCombination alt="UP" code="O" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </MenuItem> + <MenuItem fx:id="saveMenuItem" mnemonicParsing="false" onAction="#saveMenuHandler" text="%main.menuitem.save"> + <accelerator> + <KeyCodeCombination alt="UP" code="S" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </MenuItem> + <Menu fx:id="recentOpenMenu" mnemonicParsing="false" text="%main.menuitem.recentFiles" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem fx:id="profileMenu" mnemonicParsing="false" onAction="#profileMenuHandler" text="%main.menuitem.profile" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#printMenuHandler" text="%main.menuitem.print"> + <accelerator> + <KeyCodeCombination alt="UP" code="P" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator></MenuItem> + </items> + </Menu> + <Menu mnemonicParsing="false" text="%main.menu.option"> + <items> + <CheckMenuItem fx:id="dndModeMenuItem" mnemonicParsing="false" onAction="#dndModeHandler" text="%main.menuitem.dnd"> + <accelerator> + <KeyCodeCombination alt="UP" code="M" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </CheckMenuItem> + <MenuItem fx:id="errorMenu" mnemonicParsing="false" onAction="#errorMenuHandler" text="%main.menuitem.errors"> + <accelerator> + <KeyCodeCombination alt="UP" code="E" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </MenuItem> + <SeparatorMenuItem mnemonicParsing="false" /> + <MenuItem mnemonicParsing="false" onAction="#pluginMenuItemHandler" text="%main.menuitem.plugins" /> + <SeparatorMenuItem mnemonicParsing="false" /> + <CheckMenuItem fx:id="quickEditMenuItem" mnemonicParsing="false" onAction="#quickEditMenuHandler" text="Quick Edit" visible="false" /> + <MenuItem fx:id="settingsMenuItem" mnemonicParsing="false" onAction="#settingsHandler" text="%main.menuitem.settings"> + <accelerator> + <KeyCodeCombination alt="UP" code="COMMA" control="UP" meta="UP" shift="UP" shortcut="DOWN" /> + </accelerator> + </MenuItem> + </items> + </Menu> + <Menu mnemonicParsing="false" text="%main.menu.view"> + <items> + <CheckMenuItem fx:id="alwaysOnTopItem" mnemonicParsing="false" onAction="#alwaysOnTopItemHandler" text="%main.menuitem.onTop" /> + <CheckMenuItem fx:id="fullScreenMenuItem" mnemonicParsing="false" onAction="#fullScreenMenuItemHandler" text="%main.menuitem.fullScreen"> + <accelerator> + <KeyCodeCombination alt="UP" code="F" control="UP" meta="UP" shift="DOWN" shortcut="DOWN" /> + </accelerator></CheckMenuItem> + </items> + </Menu> + <Menu fx:id="extensionMenu" mnemonicParsing="false" text="%main.menu.extension" /> + <Menu mnemonicParsing="false" text="%main.menu.info"> + <items> + <MenuItem mnemonicParsing="false" onAction="#aboutMenuHandler" text="%main.menuitem.about" /> + <MenuItem mnemonicParsing="false" onAction="#visiteWebsiteMenuHandler" text="%main.menuitem.website" /> + <MenuItem mnemonicParsing="false" onAction="#sendErrorMenuItem" text="%main.menuitem.senderror" /> + </items> + </Menu> + </menus> +</MenuBar> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/main/mainToolbarView.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainToolbarView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..6688f5fbdf89a9bfd687e8d0c64c1f09825ca457 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainToolbarView.fxml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> +<?import javafx.scene.text.*?> + +<ToolBar fx:id="toolbar" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.tobias.playpad.viewcontroller.main.MainToolbarController"> + <items> + <HBox fx:id="toolbarHBox" alignment="CENTER_LEFT" maxWidth="1.7976931348623157E308" prefHeight="28.0" prefWidth="586.0" spacing="14.0"> + <children> + <HBox fx:id="pageHBox" alignment="CENTER_LEFT" spacing="14.0" HBox.hgrow="ALWAYS" /> + <HBox alignment="CENTER" spacing="7.0" HBox.hgrow="NEVER"> + <children> + <Label fx:id="volumeDownLabel"> + <font> + <Font size="24.0" /> + </font> + </Label> + <Slider fx:id="volumeSlider" focusTraversable="false" max="1.0" /> + <Label fx:id="volumeUpLabel"> + <font> + <Font size="24.0" /> + </font> + </Label> + </children> + </HBox> + </children> + </HBox> + </items> +</ToolBar> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/main/mainView.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..42936d2dd659548c8a2115bf5153f2c11155c90a --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/main/mainView.fxml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.text.*?> +<?import javafx.scene.input.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <VBox layoutX="-0.7071067690849304" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <children> + <fx:include fx:id="menuBar" source="mainMenu.fxml" /> + <fx:include fx:id="toolbar" source="mainToolbarView.fxml" /> + <AnchorPane fx:id="gridContainer" layoutX="-0.7071067690849304" layoutY="68.29289245605469" AnchorPane.bottomAnchor="-0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="69.0" VBox.vgrow="ALWAYS"> + <children> + <GridPane fx:id="padGridPane" layoutX="0.7071067690849304" layoutY="0.7071075439453125" prefHeight="331.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + </GridPane> + </children> + </AnchorPane> + </children> + </VBox> + <Label fx:id="liveLabel" alignment="CENTER" mouseTransparent="true" prefHeight="40.0" prefWidth="600.0" text="%main.label.live" textFill="RED" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="29.0"> + <font> + <Font name="System Bold" size="26.0" /> + </font> + </Label> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/mapper/keyboard.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/mapper/keyboard.fxml new file mode 100644 index 0000000000000000000000000000000000000000..628ecfc28b7461cc828d1c324329a22050c29746 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/mapper/keyboard.fxml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%keyboard.label.key" /> + <Label fx:id="keyLabel" prefWidth="68.0" text="KEY" /> + <Button fx:id="mappingButton" mnemonicParsing="false" onAction="#mappingButtonHandler" prefWidth="68.0" text="%keyboard.button.new" /> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/mapper/midi.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/mapper/midi.fxml new file mode 100644 index 0000000000000000000000000000000000000000..f0c21f66c26388cbcdebd44d7120129a5944a8b1 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/mapper/midi.fxml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + + +<VBox fx:id="root" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="18.0" layoutY="76.0" prefWidth="150.0" text="%midi.label.key" /> + <Label fx:id="midiInputKeyLabel" prefWidth="68.0" /> + <Button fx:id="midiInputRecordButton" layoutX="167.0" layoutY="71.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#midiInputRecordButtonHandler" prefWidth="68.0" text="%midi.button.new" /> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/audioTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/audioTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..86cb23c1f4f1362e39a0d79c5b87ea3147c51acd --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/audioTab.fxml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="14.0" layoutY="14.0" spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="14.0" layoutY="19.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.audio.type" /> + <ComboBox fx:id="audioTypeComboBox" layoutX="156.0" layoutY="14.0" prefHeight="26.0" prefWidth="226.0" /> + </children> + </HBox> + <AnchorPane fx:id="audioUserInfoSettings" layoutX="14.0" layoutY="53.0" prefHeight="312.0" prefWidth="617.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="53.0" /> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/doubleFeedback.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/doubleFeedback.fxml new file mode 100644 index 0000000000000000000000000000000000000000..6f57c1dc8b58e67d72b76d1880f95b59ad7a8494 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/doubleFeedback.fxml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import javafx.scene.shape.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox fx:id="defaultColorParent" maxWidth="1.7976931348623157E308" spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="24.0" layoutY="237.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%doubleFeedback.label.colorDefault" /> + <StackPane layoutX="122.0" layoutY="232.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" HBox.hgrow="ALWAYS"> + <children> + <Rectangle fx:id="colorPreviewDefault" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="26.0" layoutX="122.0" layoutY="272.0" stroke="BLACK" strokeType="INSIDE" width="128.0" StackPane.alignment="CENTER_LEFT" /> + <Button fx:id="colorChooseDefaultButton" alignment="CENTER_RIGHT" layoutX="122.0" layoutY="232.0" maxWidth="150.0" mnemonicParsing="false" onAction="#colorChooseButtonHandler" prefWidth="150.0" style="-fx-background-color: transparent;" StackPane.alignment="CENTER_LEFT" /> + </children> + </StackPane> + </children> + </HBox> + <HBox fx:id="eventColorParent" spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="24.0" layoutY="237.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%doubleFeedback.label.colorEvent" /> + <StackPane layoutX="122.0" layoutY="232.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" HBox.hgrow="ALWAYS"> + <children> + <Rectangle fx:id="colorPreviewEvent" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="26.0" layoutX="122.0" layoutY="272.0" stroke="BLACK" strokeType="INSIDE" width="128.0" StackPane.alignment="CENTER_LEFT" /> + <Button fx:id="colorChooseEventButton" alignment="CENTER_RIGHT" layoutX="122.0" layoutY="232.0" maxWidth="150.0" mnemonicParsing="false" onAction="#colorChooseButtonHandler" prefWidth="150.0" style="-fx-background-color: transparent;" StackPane.alignment="CENTER_LEFT" /> + </children> + </StackPane> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/singleFeedback.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/singleFeedback.fxml new file mode 100644 index 0000000000000000000000000000000000000000..220768e7c8a47281604d955706edb994083886fd --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/feedback/singleFeedback.fxml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import javafx.scene.shape.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox fx:id="defaultColorParent" alignment="CENTER_LEFT" maxWidth="1.7976931348623157E308" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="24.0" layoutY="237.0" prefWidth="150.0" text="%doubleFeedback.label.colorDefault" /> + <StackPane layoutX="122.0" layoutY="232.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" HBox.hgrow="ALWAYS"> + <children> + <Rectangle fx:id="colorPreviewDefault" arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="26.0" layoutX="122.0" layoutY="272.0" stroke="BLACK" strokeType="INSIDE" width="128.0" StackPane.alignment="CENTER_LEFT" /> + <Button fx:id="colorChooseDefaultButton" alignment="CENTER_RIGHT" layoutX="122.0" layoutY="232.0" maxWidth="150.0" mnemonicParsing="false" onAction="#colorChooseButtonHandler" prefWidth="150.0" style="-fx-background-color: transparent;" StackPane.alignment="CENTER_LEFT" /> + </children> + </StackPane> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/generalTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/generalTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..0e7c0a04dfb157dc027271d81c6708ebd787d6fe --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/generalTab.fxml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<VBox prefWidth="587.0" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label text="%settings.gen.label.view" underline="true" /> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="21.0" layoutY="40.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.gen.label.pages" /> + <TextField fx:id="pageCountTextField" prefWidth="50.0" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="20.0" layoutY="68.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.gen.label.columns" /> + <TextField fx:id="columnTextField" prefWidth="50.0" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="18.0" layoutY="96.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.gen.label.rows" /> + <TextField fx:id="rowTextField" prefWidth="50.0" /> + </children> + </HBox> + <Separator prefHeight="2.0" prefWidth="600.0" /> + <Label text="%settings.gen.label.additional" underline="true" /> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" maxWidth="1.7976931348623157E308" prefWidth="150.0" text="%settings.gen.label.liveMode" /> + <CheckBox fx:id="liveModeCheckBox" layoutX="30.0" layoutY="269.0" mnemonicParsing="false" text="%settings.gen.checkbox.liveMode" AnchorPane.leftAnchor="30.0" AnchorPane.topAnchor="269.0" /> + </children> + </HBox> + <Label text="%settings.gen.label.liveModeInfo" wrapText="true"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin> + </Label> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.gen.cache.label" /> + <TextField fx:id="cacheTextField" promptText="C:\Users\Max\Cache" HBox.hgrow="ALWAYS" /> + <Button mnemonicParsing="false" onAction="#cacheChooseHandler" text="%settings.gen.cache.button.choose" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label prefWidth="150.0" /> + <Button mnemonicParsing="false" onAction="#cacheResetButtonHandler" text="%settings.gen.cache.button.reset" /> + <Label fx:id="cacheSizeLabel" text="Label" /> + </children> + </HBox> + <Label text="%settings.gen.cache.label.info" wrapText="true"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin> + </Label> + <Separator prefWidth="200.0" /> + <Button alignment="TOP_LEFT" mnemonicParsing="false" onAction="#resetDialogs" text="%settings.gen.warning.button.reset"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Button> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutCart.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutCart.fxml new file mode 100644 index 0000000000000000000000000000000000000000..6b90344ea45255ee05b1260e936ca459f84becfb --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutCart.fxml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox prefHeight="100.0" prefWidth="517.0" spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <VBox alignment="BOTTOM_LEFT" maxWidth="-Infinity" prefWidth="150.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%layout.label.color" textAlignment="RIGHT" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + <VBox layoutX="110.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="110.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.background" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="backgroundColorPicker" layoutX="110.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.playground" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="playgroundColorPicker" layoutX="244.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="374.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="374.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.warnColor" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="warnColorPicker" layoutX="374.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="507.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="508.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.fadeColor" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="fadeColorPicker" layoutX="507.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + </children> + </HBox> + <Separator prefHeight="3.0" prefWidth="600.0" /> + <HBox spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <VBox alignment="BOTTOM_LEFT" layoutX="26.0" layoutY="184.0" prefWidth="150.0" spacing="23.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="26.0" layoutY="184.0" prefWidth="150.0" text="%layout.label.color" textAlignment="RIGHT" AnchorPane.leftAnchor="26.0" /> + </children> + <HBox.margin> + <Insets bottom="7.0" /> + </HBox.margin> + </VBox> + <VBox layoutX="109.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="TOP_CENTER" layoutX="109.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.infoLabel" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="infoLabelColorPicker" layoutX="109.0" layoutY="179.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="TOP_CENTER" layoutX="243.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.titleLabel" AnchorPane.leftAnchor="243.0" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="titleLabelColorPicker" layoutX="243.0" layoutY="179.0" maxWidth="1.7976931348623157E308" AnchorPane.leftAnchor="243.0" /> + </children> + </VBox> + <VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" HBox.hgrow="ALWAYS" /> + <VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + <Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonHandler" text="%layout.button.reset"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Button> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutGlobal.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutGlobal.fxml new file mode 100644 index 0000000000000000000000000000000000000000..31b762d687e55fa46cb2b26b38753ad090174797 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/classicLayoutGlobal.fxml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox spacing="14.0"> + <children> + <VBox spacing="14.0"> + <children> + <HBox alignment="CENTER_LEFT" layoutX="23.0" layoutY="193.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="23.0" layoutY="198.0" minWidth="150.0" prefWidth="150.0" text="%layout.label.programmLayout" /> + <ComboBox fx:id="programLayoutComboBox" layoutX="134.0" layoutY="193.0" prefWidth="150.0" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" layoutX="23.0" layoutY="225.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="23.0" layoutY="226.0" minWidth="150.0" prefWidth="150.0" text="%layout.label.customLayout" /> + <CheckBox fx:id="customLayoutCheckBox" layoutX="134.0" layoutY="225.0" mnemonicParsing="false" text="%settings.checkbox.activate" /> + </children> + </HBox> + </children> + </VBox> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="362.0" layoutY="193.0" prefWidth="150.0" text="%layout.label.baseColor" /> + <ColorPicker fx:id="accentColorChooser" layoutX="420.0" layoutY="196.0" /> + </children> + </HBox> + </children> + </HBox> + <VBox fx:id="customizeView" spacing="14.0"> + <children> + <Separator prefWidth="200.0" /> + <HBox prefWidth="517.0" spacing="14.0"> + <children> + <VBox alignment="BOTTOM_LEFT" prefWidth="150.0"> + <children> + <Label alignment="CENTER_RIGHT" maxWidth="1.7976931348623157E308" text="%layout.label.color" VBox.vgrow="ALWAYS" /> + </children> + </VBox> + <VBox layoutX="110.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="110.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.background" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="backgroundColorPicker" layoutX="110.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.playground" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="playgroundColorPicker" layoutX="244.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="374.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="374.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.warnColor" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="warnColorPicker" layoutX="374.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="507.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="508.0" layoutY="8.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" text="%layout.label.fadeColor" wrapText="true" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="fadeColorPicker" layoutX="507.0" layoutY="68.0" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + </children> + </HBox> + <Separator prefHeight="3.0" prefWidth="600.0" /> + <HBox spacing="14.0"> + <children> + <VBox alignment="BOTTOM_LEFT" layoutX="26.0" layoutY="184.0" prefWidth="150.0" spacing="23.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="26.0" layoutY="184.0" maxWidth="1.7976931348623157E308" text="%layout.label.color" AnchorPane.leftAnchor="26.0" VBox.vgrow="ALWAYS" /> + <Label alignment="CENTER_RIGHT" layoutX="26.0" layoutY="224.0" maxWidth="1.7976931348623157E308" text="%layout.label.fontSize" AnchorPane.leftAnchor="26.0" VBox.vgrow="ALWAYS" /> + </children> + <HBox.margin> + <Insets bottom="7.0" /> + </HBox.margin> + </VBox> + <VBox layoutX="109.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="TOP_CENTER" layoutX="109.0" layoutY="154.0" maxWidth="1.7976931348623157E308" text="%layout.label.infoLabel" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="infoLabelColorPicker" layoutX="109.0" layoutY="179.0" maxWidth="1.7976931348623157E308" /> + <ComboBox fx:id="infoLabelFontSizeComboBox" editable="true" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="154.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="TOP_CENTER" layoutX="243.0" layoutY="154.0" maxWidth="1.7976931348623157E308" text="%layout.label.titleLabel" AnchorPane.leftAnchor="243.0" VBox.vgrow="ALWAYS" /> + <ColorPicker fx:id="titleLabelColorPicker" layoutX="243.0" layoutY="179.0" maxWidth="1.7976931348623157E308" AnchorPane.leftAnchor="243.0" /> + <ComboBox fx:id="titleLabelFontSizeComboBox" editable="true" maxWidth="1.7976931348623157E308" /> + </children> + </VBox> + <VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" HBox.hgrow="ALWAYS" /> + <VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="100.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + </children> + </VBox> + <Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonHandler" text="%layout.button.reset"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Button> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutCart.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutCart.fxml new file mode 100644 index 0000000000000000000000000000000000000000..47f1ad840bd6cebeedff224dff9332c4c32d01a4 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutCart.fxml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.shape.*?> +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox spacing="14.0"> + <children> + <VBox alignment="BOTTOM_LEFT" prefWidth="150.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%layout.label.color" VBox.vgrow="ALWAYS"> + <VBox.margin> + <Insets bottom="5.0" /> + </VBox.margin></Label> + </children> + </VBox> + <VBox layoutX="110.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="125.0" spacing="14.0"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="110.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.background" wrapText="true" VBox.vgrow="ALWAYS" /> + <Button fx:id="backgroundColorButton" focusTraversable="false" mnemonicParsing="false" onAction="#backgroundColorButtonHandler" prefWidth="150.0" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="125.0" spacing="14.0"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.playground" wrapText="true" VBox.vgrow="ALWAYS" /> + <Button fx:id="playColorButton" focusTraversable="false" mnemonicParsing="false" onAction="#playColorButtonHandler" prefWidth="150.0" /> + </children> + </VBox> + <VBox maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.animation" wrapText="true" VBox.vgrow="ALWAYS" /> + <CheckBox fx:id="warnAnimationCheckBox" mnemonicParsing="false" text="%layout.label.warnAnimation" /> + </children> + </VBox> + </children> + </HBox> + <Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonHandler" text="%layout.button.reset"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Button> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutGlobal.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutGlobal.fxml new file mode 100644 index 0000000000000000000000000000000000000000..c80cc9f2edd3d4183eb2ed67078c54c9fc22f799 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/layout/modernLayoutGlobal.fxml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.shape.*?> +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox prefHeight="100.0" prefWidth="517.0" spacing="14.0"> + <children> + <VBox alignment="BOTTOM_LEFT" prefWidth="150.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%layout.label.color" VBox.vgrow="ALWAYS"> + <VBox.margin> + <Insets bottom="5.0" /> + </VBox.margin></Label> + </children> + </VBox> + <VBox layoutX="110.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="110.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.background" wrapText="true" VBox.vgrow="ALWAYS" /> + <Button fx:id="backgroundColorButton" focusTraversable="false" mnemonicParsing="false" onAction="#backgroundColorButtonHandler" prefWidth="150.0" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="8.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.playground" wrapText="true" VBox.vgrow="ALWAYS" /> + <Button fx:id="playColorButton" focusTraversable="false" mnemonicParsing="false" onAction="#playColorButtonHandler" prefWidth="150.0" /> + </children> + </VBox> + <VBox maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0"> + <children> + <Label alignment="BOTTOM_LEFT" layoutX="243.0" layoutY="8.0" prefHeight="60.0" prefWidth="150.0" text="%layout.label.animation" wrapText="true" VBox.vgrow="ALWAYS" /> + <CheckBox fx:id="warnAnimationCheckBox" mnemonicParsing="false" text="%layout.label.warnAnimation" /> + </children> + </VBox> + </children> + </HBox> + <Separator prefHeight="3.0" prefWidth="600.0" /> + <HBox spacing="14.0"> + <children> + <VBox alignment="BOTTOM_LEFT" layoutX="26.0" layoutY="184.0" prefWidth="150.0" spacing="23.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="26.0" layoutY="224.0" prefWidth="150.0" text="%layout.label.fontSize" AnchorPane.leftAnchor="26.0" /> + </children> + <HBox.margin> + <Insets bottom="7.0" /> + </HBox.margin> + </VBox> + <VBox layoutX="109.0" layoutY="154.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0"> + <children> + <Label alignment="TOP_CENTER" layoutX="109.0" layoutY="154.0" maxWidth="1.7976931348623157E308" text="%layout.label.infoLabel" VBox.vgrow="ALWAYS" /> + <ComboBox fx:id="infoLabelFontSizeComboBox" editable="true" prefWidth="150.0" /> + </children> + </VBox> + <VBox layoutX="243.0" layoutY="154.0" maxWidth="1.7976931348623157E308" prefWidth="150.0" spacing="14.0"> + <children> + <Label alignment="TOP_CENTER" layoutX="243.0" layoutY="154.0" maxWidth="1.7976931348623157E308" text="%layout.label.titleLabel" AnchorPane.leftAnchor="243.0" VBox.vgrow="ALWAYS" /> + <ComboBox fx:id="titleLabelFontSizeComboBox" editable="true" prefWidth="150.0" /> + </children> + </VBox> + </children> + </HBox> + <Button fx:id="resetButton" mnemonicParsing="false" onAction="#resetButtonHandler" text="%layout.button.reset"> + <VBox.margin> + <Insets left="164.0" /> + </VBox.margin></Button> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/layoutTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/layoutTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..c7049d4e4e458c03cc31508d39effa8ef640a028 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/layoutTab.fxml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox alignment="CENTER_LEFT" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%settings.layout.label.type" /> + <ComboBox fx:id="layoutTypeComboBox" prefWidth="150.0" /> + </children> + <VBox.margin> + <Insets /> + </VBox.margin> + </HBox> + <VBox fx:id="layoutContainer" maxWidth="1.7976931348623157E308" prefHeight="20.0" VBox.vgrow="ALWAYS" /> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/mapping.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/mapping.fxml new file mode 100644 index 0000000000000000000000000000000000000000..376799ae457ad29e9f71975036d099b65277c6bf --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/mapping.fxml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="14.0" layoutY="14.0" spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" layoutX="14.0" layoutY="19.0" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%settings.mapping.label.mapping" /> + <ComboBox fx:id="mappingComboBox" layoutX="100.0" layoutY="14.0" prefWidth="150.0" /> + <Button fx:id="editMappingsButton" layoutX="264.0" layoutY="14.0" mnemonicParsing="false" onAction="#editMappingsHandler" text="%settings.mapping.button.edit" /> + </children> + </HBox> + <HBox layoutY="50.0" spacing="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="50.0"> + <children> + <TreeView fx:id="treeView" prefHeight="400.0" prefWidth="200.0" showRoot="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="50.0" /> + <ScrollPane fitToWidth="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: transparent;" HBox.hgrow="ALWAYS"> + <content> + <VBox fx:id="detailView" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" spacing="14.0" /> + </content> + </ScrollPane> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..c65c10d53e6eac505cc56160ada1d49e3a428287 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab.fxml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.shape.*?> +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%settings.midi.label.device"> + <HBox.margin> + <Insets top="4.0" /> + </HBox.margin> + </Label> + <HBox maxWidth="1.7976931348623157E308" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <ComboBox fx:id="deviceComboBox" onAction="#deviceHandler" prefWidth="150.0" /> + <Pane HBox.hgrow="ALWAYS" /> + <CheckBox fx:id="midiActiveCheckBox" mnemonicParsing="false" text="%settings.checkbox.activate"> + <padding> + <Insets top="5.0" /> + </padding> + <HBox.margin> + <Insets top="4.0" /> + </HBox.margin> + </CheckBox> + </children> + </HBox> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab_old.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab_old.fxml new file mode 100644 index 0000000000000000000000000000000000000000..5923d8e0a7b57dd5fb8b9142528faf0ad80c962b --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/midiTab_old.fxml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane fx:id="rootPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="34.0" layoutY="34.0" prefHeight="67.0" prefWidth="523.0" spacing="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <VBox alignment="CENTER_RIGHT" layoutX="9.0" layoutY="19.0" prefHeight="67.0" spacing="25.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <Label layoutX="9.0" layoutY="19.0" text="%settings.midi.label.device" /> + <Label layoutX="11.0" layoutY="51.0" text="%settings.midi.label.preset" /> + </children> + </VBox> + <VBox layoutX="127.0" layoutY="14.0" maxWidth="1.7976931348623157E308" spacing="14.0" HBox.hgrow="ALWAYS"> + <children> + <HBox alignment="CENTER_LEFT" layoutX="127.0" layoutY="14.0" maxWidth="1.7976931348623157E308" spacing="14.0" AnchorPane.leftAnchor="127.0" AnchorPane.rightAnchor="121.0" VBox.vgrow="ALWAYS"> + <children> + <ComboBox fx:id="deviceComboBox" onAction="#deviceHandler" prefWidth="150.0" /> + <Pane HBox.hgrow="ALWAYS" /> + <CheckBox fx:id="midiActiveCheckBox" mnemonicParsing="false" text="%settings.checkbox.activate" /> + </children> + </HBox> + <HBox layoutX="127.0" layoutY="47.0" maxWidth="1.7976931348623157E308" spacing="14.0" VBox.vgrow="ALWAYS"> + <children> + <ComboBox fx:id="presetsList" layoutX="127.0" layoutY="47.0" prefWidth="150.0" /> + <Button fx:id="presetsEditButton" layoutX="304.0" layoutY="47.0" mnemonicParsing="false" onAction="#presetsEditButtonHandler" text="%settings.midi.presetEdit" /> + <Button fx:id="activateButton" mnemonicParsing="false" onAction="#activateButtonHandler" text="%settings.midi.button.activate" /> + </children> + </HBox> + </children> + </VBox> + </children> + </HBox> + <TreeView fx:id="contentTreeView" prefHeight="375.0" prefWidth="300.0" AnchorPane.bottomAnchor="135.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="90.0" /> + <ComboBox fx:id="midiActionTypeComboBox" layoutX="312.0" layoutY="90.0" prefWidth="264.0" AnchorPane.leftAnchor="314.0" /> + <AnchorPane fx:id="settingsAnchorPane" layoutX="306.0" layoutY="133.0" prefHeight="467.0" prefWidth="300.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="300.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="133.0" /> + <HBox layoutX="14.0" layoutY="534.0" prefHeight="52.0" prefWidth="281.0" spacing="14.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0"> + <children> + <VBox spacing="14.0"> + <children> + <Button fx:id="addMidiButton" defaultButton="true" layoutX="14.0" layoutY="319.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#addMidiButtonHandler" text="%settings.midi.button.add" AnchorPane.bottomAnchor="56.0" AnchorPane.leftAnchor="14.0" /> + <Button fx:id="addMidiDraftButton" layoutX="14.0" layoutY="354.0" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#addMidiDraftButtonHandler" text="%settings.midi.button.addDraft" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="14.0" /> + <Button fx:id="draftButton" mnemonicParsing="false" onAction="#draftButtonHandler" text="%settings.midi.button.saveDraft" /> + </children> + </VBox> + <VBox spacing="14.0"> + <children> + <Button fx:id="deleteMidiButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#deleteMidiButtonHandler" text="%settings.midi.button.delete" /> + <Button fx:id="clearMidiButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#clearMidiButtonHandler" prefHeight="26.0" prefWidth="68.0" text="%settings.midi.button.clear" /> + </children> + </VBox> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/generalTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/generalTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..5e3012693a20acdcf1b1b400e7176d1b37631f31 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/generalTab.fxml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <VBox layoutX="14.0" layoutY="14.0" spacing="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="14.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="19.0" prefWidth="150.0" text="%padSettings.gen.label.title" AnchorPane.leftAnchor="14.0" /> + <TextField fx:id="titleTextField" layoutX="125.0" layoutY="14.0" prefWidth="250.0" AnchorPane.leftAnchor="127.0" /> + <VBox HBox.hgrow="ALWAYS" /> + <Button fx:id="deleteButton" mnemonicParsing="false" onAction="#deleteButtonHandler" text="%padSettings.button.delete" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="48.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="50.0" prefWidth="150.0" text="%padSettings.gen.label.volume" AnchorPane.leftAnchor="14.0" /> + <Slider fx:id="volumeSlider" layoutX="122.0" layoutY="54.0" prefWidth="250.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="100.0" AnchorPane.leftAnchor="127.0" /> + <VBox HBox.hgrow="ALWAYS" /> + <CheckBox fx:id="repeatCheckBox" mnemonicParsing="false" text="%padSettings.checkbox.loop" /> + </children> + </HBox> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="84.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="89.0" prefWidth="150.0" text="%padSettings.gen.label.timeDisplay" AnchorPane.leftAnchor="14.0" /> + <ComboBox fx:id="timeDisplayComboBox" layoutX="127.0" layoutY="84.0" prefWidth="250.0" AnchorPane.leftAnchor="127.0" /> + <VBox HBox.hgrow="ALWAYS" /> + <CheckBox fx:id="customTimeDisplayCheckBox" layoutX="406.0" layoutY="88.0" mnemonicParsing="false" text="%padSettings.gen.checkbox.customSettings" /> + </children> + </HBox> + </children> + </VBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/layoutTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/layoutTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..649480a0b2de5432e38f7342dd7b1bbafa527cf0 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/layoutTab.fxml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="14.0" layoutY="13.0" spacing="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="14.0" prefWidth="150.0" text="%padSettings.layout.label.custom" /> + <CheckBox fx:id="enableLayoutCheckBox" layoutX="127.0" layoutY="13.0" mnemonicParsing="false" text="%padSettings.layout.checkbox.custom" /> + </children> + <VBox.margin> + <Insets /> + </VBox.margin> + </HBox> + <VBox fx:id="layoutContainer" prefHeight="200.0" prefWidth="100.0" /> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/padSettingsView.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/padSettingsView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..3de2d6271f86b985d4d36a09f7de44e67489dbe4 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/padSettingsView.fxml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <TabPane fx:id="tabPane" prefHeight="484.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="53.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <Button fx:id="finishButton" defaultButton="true" layoutX="534.0" layoutY="497.0" mnemonicParsing="false" onAction="#finishButtonHandler" text="%padSettings.button.finish" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" /> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/playerTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/playerTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4c4a693ff9e3adedf6579f70a46e46a8c39b3b41 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/playerTab.fxml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <VBox spacing="14.0"> + <children> + <HBox layoutX="14.0" layoutY="253.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%padSettings.player.label.fade" textAlignment="RIGHT" /> + <CheckBox fx:id="customFadeCheckBox" mnemonicParsing="false" text="%padSettings.gen.checkbox.customSettings" /> + </children> + </HBox> + </children> + </VBox> + <VBox fx:id="fadeContainer" minHeight="20.0" /> + <Separator prefWidth="200.0" /> + <VBox layoutX="14.0" layoutY="139.0" spacing="14.0"> + <children> + <HBox layoutX="14.0" layoutY="139.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%padSettings.player.label.warning" textAlignment="RIGHT" /> + <CheckBox fx:id="warningEnableCheckBox" mnemonicParsing="false" text="%padSettings.gen.checkbox.customSettings" /> + </children> + </HBox> + <VBox fx:id="warningFeedbackContainer" minHeight="25.0" /> + </children> + </VBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/cartTrigger.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/cartTrigger.fxml new file mode 100644 index 0000000000000000000000000000000000000000..3aee2f7dda47d7fcd51ad973ddb0a0a4a4ea055b --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/cartTrigger.fxml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox spacing="14.0"> + <children> + <Label alignment="BASELINE_RIGHT" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%carttrigger.label.action" /> + <ComboBox fx:id="statusComboBox" prefWidth="150.0" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <Label alignment="TOP_RIGHT" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%carttrigger.label.carts" /> + <VBox spacing="14.0"> + <children> + <CheckBox fx:id="allCartsCheckbox" mnemonicParsing="false" text="%carttrigger.checkbox.all" /> + <TextField fx:id="cartTextField" prefWidth="150.0" promptText="1, 3-5" /> + </children> + </VBox> + </children> + </HBox> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerPoint.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerPoint.fxml new file mode 100644 index 0000000000000000000000000000000000000000..14672bf25973b06c9e55e4404d99719c5b035326 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerPoint.fxml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <ScrollPane fitToWidth="true" maxWidth="1.7976931348623157E308" prefViewportHeight="20.0" prefViewportWidth="100.0" style="-fx-background-color: transparent;" VBox.vgrow="ALWAYS"> + <content> + <VBox fx:id="itemView" minHeight="20.0" minWidth="100.0" spacing="14.0" /> + </content> + </ScrollPane> + <HBox fx:id="buttonBox" minHeight="10.0" spacing="14.0" /> + </children> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerTime.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerTime.fxml new file mode 100644 index 0000000000000000000000000000000000000000..1b38ff3c2f2810a912106725ed630eaa0e4f2456 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/trigger/triggerTime.fxml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label alignment="BASELINE_RIGHT" maxHeight="1.7976931348623157E308" prefWidth="150.0" text="%triggertime.label.time" /> + <TextField fx:id="timeTextField" prefWidth="150.0" /> + </children> +</HBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/triggerTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/triggerTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..e015d3a7d7ebfd570af1fe9fc500975d52ce28a5 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/pad/triggerTab.fxml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <TreeView fx:id="treeView" showRoot="false" /> + <VBox fx:id="contentView" minWidth="100.0" HBox.hgrow="ALWAYS"> + <HBox.margin> + <Insets left="14.0" right="14.0" top="14.0" /> + </HBox.margin> + </VBox> + </children> +</HBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/playerTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/playerTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..9c906697b32ec661415ee0eb9ce42c57d78873a9 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/playerTab.fxml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import java.lang.*?> +<?import javafx.scene.control.*?> +<?import javafx.scene.layout.*?> + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Label text="%settings.player.label.warning" underline="true" /> + <VBox fx:id="warningFeedbackContainer" minHeight="25.0" /> + <Separator prefWidth="200.0" /> + <Label text="%settings.player.label.fade" underline="true" /> + <VBox fx:id="fadeContainer" minHeight="20.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" /> + <Separator layoutY="91.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" /> + <HBox alignment="CENTER_LEFT" layoutX="14.0" layoutY="105.0" spacing="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="110.0" minWidth="150.0" prefWidth="150.0" text="%settings.player.label.timeDisplay" /> + <ComboBox fx:id="timeDisplayComboBox" layoutX="104.0" layoutY="105.0" prefHeight="26.0" prefWidth="254.0" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/settingsView.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/settingsView.fxml new file mode 100644 index 0000000000000000000000000000000000000000..23efae52a75f75d6b931db277299917bba3eea67 --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/settingsView.fxml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="592.0" prefWidth="645.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <TabPane fx:id="tabPane" prefHeight="348.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="52.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> + <Button fx:id="finishButton" layoutX="508.0" layoutY="360.0" mnemonicParsing="false" onAction="#finishButtonHandler" text="%settings.button.finish" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" /> + </children> +</AnchorPane> diff --git a/PlayWall/assets/de/tobias/playpad/assets/view/option/updateTab.fxml b/PlayWall/assets/de/tobias/playpad/assets/view/option/updateTab.fxml new file mode 100644 index 0000000000000000000000000000000000000000..91c68b8a000fcfe5f6028a2d03f1ab06a68131cf --- /dev/null +++ b/PlayWall/assets/de/tobias/playpad/assets/view/option/updateTab.fxml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.*?> +<?import javafx.scene.control.*?> +<?import java.lang.*?> +<?import javafx.scene.layout.*?> + + +<VBox spacing="14.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <HBox layoutX="14.0" layoutY="14.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="14.0" prefWidth="150.0" text="%settings.update.label.current" /> + <Label fx:id="currentVersionLabel" layoutX="175.0" layoutY="14.0" text="5.0.1 (stable)" /> + </children> + </HBox> + <HBox layoutX="14.0" layoutY="36.0" spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="14.0" layoutY="36.0" prefWidth="150.0" text="%settings.update.label.new" /> + <Label fx:id="newVersionLabel" layoutX="175.0" layoutY="36.0" text="5.0.2 (stable)" /> + </children> + </HBox> + <Separator prefWidth="200.0" /> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="106.0" layoutY="183.0" prefWidth="150.0" text="%settings.update.label.search" /> + <CheckBox fx:id="automaticSearchCheckBox" layoutX="275.0" layoutY="183.0" mnemonicParsing="false" text="Automatisch" /> + </children> + </HBox> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" layoutX="106.0" layoutY="222.0" prefWidth="150.0" /> + <Button fx:id="manualSearchButton" layoutX="275.0" layoutY="217.0" mnemonicParsing="false" onAction="#manualSearchHandler" text="%settings.update.button.search" /> + </children> + </HBox> + <Separator prefWidth="200.0" /> + <HBox spacing="14.0"> + <children> + <Label alignment="CENTER_RIGHT" prefWidth="150.0" text="%settings.update.label.available" /> + <ListView fx:id="openUpdateList" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" /> + </children> + </HBox> + <HBox alignment="TOP_RIGHT"> + <children> + <Button fx:id="updateButton" mnemonicParsing="false" onAction="#updateHandler" text="%settings.update.button.install" /> + </children> + </HBox> + </children> + <padding> + <Insets bottom="14.0" left="14.0" right="14.0" top="14.0" /> + </padding> +</VBox> diff --git a/PlayWall/src/application.yml b/PlayWall/src/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..8c4c7d52ea06939be86818ed0ebb573f90415f5e --- /dev/null +++ b/PlayWall/src/application.yml @@ -0,0 +1,15 @@ +name: PlayWall +version: b5.0.0 +build: 24 +identifier: de.tobias.playpad +main: de.tobias.playpad.PlayPadMain +author: Tobias Ullerich +backup: false +iconPath: icon +updateURL: http://s522730663.online.de/programmer/files/PlayWall +userInfo: + Website: http://tobisan.no-ip.org/ + ErrorURL: http://s522730663.online.de/programmer/upload.php + PluginsURL: http://s522730663.online.de/programmer/files/PlayWall/plugins.yml + ChangelogURL: http://s522730663.online.de/programmer/whatsnew-2.php?id=1 + UpdaterProgram: http://s522730663.online.de/programmer/files/Updater/ diff --git a/PlayWall/src/controlsfx_de_DE.properties b/PlayWall/src/controlsfx_de_DE.properties new file mode 100644 index 0000000000000000000000000000000000000000..3416523e7ebdad7ee87d1388e65e7287ce7cf2d0 --- /dev/null +++ b/PlayWall/src/controlsfx_de_DE.properties @@ -0,0 +1,70 @@ +### Dialogs ### + +dlg.ok.button = OK +dlg.cancel.button = Abbruch +dlg.yes.button = Ja +dlg.no.button = Nein +dlg.close.button = Schlie�en +dlg.detail.button.more = Show Details +dlg.detail.button.less = Hide Details + +### Common Dialogs ### + +font.dlg.title=Select font +font.dlg.header=Select font +font.dlg.sample.text=Sample +font.dlg.font.label=Font +font.dlg.style.label=Style +font.dlg.size.label=Size + +progress.dlg.title=Progress +progress.dlg.header=Progress + +login.dlg.title=Login +login.dlg.header=Enter user name and password +login.dlg.user.caption=User Name +login.dlg.pswd.caption=Password +login.dlg.login.button=Login + +exception.dlg.title = Exception Details +exception.dlg.header = Exception Details +exception.dlg.label = The exception stacktrace was: +exception.button.label = Open Exception + +### Wizard ### + +wizard.next.button = Weiter +wizard.previous.button = Zur�ck + +### Property Sheet ### + +bean.property.change.error.title = Property Change Error +bean.property.change.error.header = Change is not allowed +bean.property.category.basic=Basic +bean.property.category.expert=Expert + +property.sheet.search.field.prompt = Search +property.sheet.group.mode.byname = By Name +property.sheet.group.mode.bycategory = By Category + +### Spreadsheet View ### + +spreadsheet.view.menu.copy = Copy +spreadsheet.view.menu.paste = Paste +spreadsheet.view.menu.comment = Comment cell +spreadsheet.view.menu.comment.top-left = top left +spreadsheet.view.menu.comment.top-right = top right +spreadsheet.view.menu.comment.bottom-right = bottom right +spreadsheet.view.menu.comment.bottom-left = bottom left +spreadsheet.column.menu.fix = Fix column +spreadsheet.column.menu.unfix = Unfix column +spreadsheet.verticalheader.menu.fix = Fix row +spreadsheet.verticalheader.menu.unfix = Unfix row + +### Status Bar ### +statusbar.ok = OK + +### List Selection View ### +listSelectionView.header.source = Available +listSelectionView.header.target = Selected + diff --git a/PlayWall/src/de/tobias/playpad/AppUserInfoStrings.java b/PlayWall/src/de/tobias/playpad/AppUserInfoStrings.java new file mode 100644 index 0000000000000000000000000000000000000000..df966939ee73d71abe043ee02b458093900bced8 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/AppUserInfoStrings.java @@ -0,0 +1,10 @@ +package de.tobias.playpad; + +public class AppUserInfoStrings { + + public static final String WEBSITE = "Website"; + public static final String PLUGINS_URL = "PluginsURL"; + public static final String ERROR_URL = "ErrorURL"; + public static final String CHANGELOG_URL = "ChangelogURL"; + public static final String UPDATER_PROGRAM = "UpdaterProgram"; +} diff --git a/PlayWall/src/de/tobias/playpad/PlayPadMain.java b/PlayWall/src/de/tobias/playpad/PlayPadMain.java new file mode 100644 index 0000000000000000000000000000000000000000..81e098fd6605ccd1fc4e045f2f657285a8c07e8b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/PlayPadMain.java @@ -0,0 +1,460 @@ +package de.tobias.playpad; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.UUID; + +import de.tobias.playpad.action.ActionRegistery; +import de.tobias.playpad.action.connect.CartActionConnect; +import de.tobias.playpad.action.connect.NavigateActionConnect; +import de.tobias.playpad.action.connect.PageActionConnect; +import de.tobias.playpad.action.mapper.KeyboardMapperConnect; +import de.tobias.playpad.action.mapper.MapperRegistry; +import de.tobias.playpad.action.mapper.MidiMapperConnect; +import de.tobias.playpad.audio.AudioRegistry; +import de.tobias.playpad.audio.ClipAudioHandler; +import de.tobias.playpad.audio.ClipAudioHandlerConnect; +import de.tobias.playpad.audio.JavaFXAudioHandler; +import de.tobias.playpad.audio.JavaFXHandlerConnect; +import de.tobias.playpad.audio.TinyAudioHandler; +import de.tobias.playpad.audio.TinyAudioHandlerConnect; +import de.tobias.playpad.layout.LayoutRegistry; +import de.tobias.playpad.layout.classic.ClassicGlobalLayout; +import de.tobias.playpad.layout.classic.ClassicLayoutConnect; +import de.tobias.playpad.layout.modern.ModernLayoutConnect; +import de.tobias.playpad.midi.device.DeviceRegistry; +import de.tobias.playpad.midi.device.PD12; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.content.AudioContentConnect; +import de.tobias.playpad.pad.drag.MoveDragMode; +import de.tobias.playpad.pad.drag.PadDragModeRegistery; +import de.tobias.playpad.pad.drag.ReplaceDragMode; +import de.tobias.playpad.plugin.PadListener; +import de.tobias.playpad.plugin.SettingsListener; +import de.tobias.playpad.plugin.WindowListener; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileListener; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.playpad.tigger.TriggerRegistry; +import de.tobias.playpad.trigger.CartTriggerItemConnect; +import de.tobias.playpad.view.MapperOverviewViewController; +import de.tobias.playpad.viewcontroller.IPadSettingsViewController; +import de.tobias.playpad.viewcontroller.ISettingsViewController; +import de.tobias.playpad.viewcontroller.LaunchDialog; +import de.tobias.playpad.viewcontroller.dialog.ChangelogDialog; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.playpad.viewcontroller.main.MainViewController; +import de.tobias.playpad.viewcontroller.option.UpdateTabViewController; +import de.tobias.utils.application.App; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.ConsoleUtils; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Localization.LocalizationDelegate; +import de.tobias.utils.util.Worker; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonType; +import javafx.scene.image.Image; +import javafx.stage.Stage; +import net.xeoh.plugins.base.PluginManager; +import net.xeoh.plugins.base.impl.PluginManagerFactory; + +/* + * TODOS + */ +// PlayWall 5.0.0 +// FIXME XML Tags in String Konstanten + +// Common Updater für Plugins & Programme +// Changelog OK Button +// Keine Schriftgröße bei Cart Layout + +// Profile mit UUID + +// FEATURE Backups irgendwann löschen + +// Pad System neu machen +// Neue PadViewController für jedes pad +// Midi Modell Überarbeiten +// Bei Seitenwechsel Pad auf Play lassen + +// FEATURE Trigger + +// FEATURE Option bei Import Media auch Copy Media in Library + +// FEATURE lnk für Windows mit Dateiparameter + +// FEATURE PFL +// FEATURE Sound Card Pro Cart + +public class PlayPadMain extends Application implements LocalizationDelegate, PlayPad, ProfileListener { + + private static final String iconPath = "icon_small.png"; + public static Optional<Image> stageIcon = Optional.empty(); + + public static final long notificationDisplayTimeMillis = 1500; + + public static final String[] projectType = { "*.xml" }; + public static final String[] projectCompressedType = { "*.zip" }; + public static final String[] midiPresetType = { "*.pre" }; + + private static ResourceBundle uiResourceBundle; + private static MainViewController mainViewController; + + private static PlayPadUpdater updater; + private static Set<Path> deletedPlugins = new HashSet<>(); + + public static void addDeletedPlugin(Path path) { + deletedPlugins.add(path); + } + + /* + * + */ + + public static ResourceBundle getUiResourceBundle() { + return uiResourceBundle; + } + + public static void main(String[] args) throws Exception { + // Debug + System.setOut(ConsoleUtils.convertStream(System.out, "[PlayWall] ")); + System.setErr(ConsoleUtils.convertStream(System.err, "[PlayWall] ")); + + App app = ApplicationUtils.registerMainApplication(PlayPadMain.class); + ApplicationUtils.registerUpdateSercive(new VersionUpdater()); + app.start(args); + } + + private static PluginManager pluginManager; + + @Override + public void init() throws Exception { + PlayPadPlugin.setImplementation(this); + + // Localization + setupLocalization(); + + // Console + if (!ApplicationUtils.getApplication().isDebug()) { + System.setOut(ConsoleUtils.streamToFile(ApplicationUtils.getApplication().getPath(PathType.LOG, "out.log"))); + System.setErr(ConsoleUtils.streamToFile(ApplicationUtils.getApplication().getPath(PathType.LOG, "err.log"))); + } + } + + @Override + public void start(Stage stage) throws Exception { + // Assets + try { + Image stageIcon = new Image(iconPath); + PlayPadMain.stageIcon = Optional.of(stageIcon); + } catch (Exception e) {} + + /* + * Setup + */ + updater = new PlayPadUpdater(); + UpdateRegistery.registerUpdateable(updater); + registerComponents(); + setupPlugins(); + + /* + * Load Data + */ + ProfileReference.loadProfiles(); + ProjectReference.loadProjects(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> + { + try { + if (mainViewController != null) { + if (mainViewController.getProject().getRef() != null) { + // Projekt Speichern + mainViewController.getProject().save(); + } + } + + if (Profile.currentProfile() != null) + Profile.currentProfile().save(); + + ProfileReference.saveProfiles(); + ProjectReference.saveProjects(); + } catch (Exception e) { + e.printStackTrace(); // Speichern Fehler + } + })); + + // Changelog nach Update anzeigen + try { + ViewController.create(ChangelogDialog.class); + } catch (Exception e) { + e.printStackTrace(); + } + + // Auto Open Project + if (getParameters().getRaw().size() > 0) { + try { + UUID uuid = UUID.fromString(getParameters().getRaw().get(0)); + launchProject(Project.load(ProjectReference.getProject(uuid), true, null)); + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + + ViewController.create(LaunchDialog.class, stage); + } + + private void registerComponents() { + // Audio + AudioRegistry.register(new JavaFXHandlerConnect(), JavaFXAudioHandler.NAME); + AudioRegistry.register(new TinyAudioHandlerConnect(), TinyAudioHandler.NAME); + AudioRegistry.register(new ClipAudioHandlerConnect(), ClipAudioHandler.NAME); + + AudioRegistry.setDefaultAudioInterface(JavaFXAudioHandler.NAME); + + // Layout + LayoutRegistry.registerLayout(new ClassicLayoutConnect()); + LayoutRegistry.registerLayout(new ModernLayoutConnect()); + LayoutRegistry.setDefaultLayout(ClassicGlobalLayout.TYPE); + + // Midi + DeviceRegistry.getFactoryInstance().registerDevice(PD12.NAME, PD12.class); + + // Trigger + TriggerRegistry.register(new CartTriggerItemConnect()); +// TriggerRegistry.register(new VolumeTriggerItemConnect()); + + // Actions + ActionRegistery.registerActionConnect(new CartActionConnect()); + ActionRegistery.registerActionConnect(new PageActionConnect()); + ActionRegistery.registerActionConnect(new NavigateActionConnect()); + + // Mapper + MapperRegistry.registerMapperConnect(new MidiMapperConnect()); + MapperRegistry.registerMapperConnect(new KeyboardMapperConnect()); + MapperRegistry.setOverviewViewController(new MapperOverviewViewController()); + + // Pad Content + PadContentRegistry.registerActionConnect(new AudioContentConnect()); + + // Pad Drag Mode + PadDragModeRegistery.registerActionConnect(new MoveDragMode()); + PadDragModeRegistery.registerActionConnect(new ReplaceDragMode()); + + Profile.registerListener(this); + } + + private void setupPlugins() throws IOException, MalformedURLException { + /* + * Plugins + */ + Path pluginInfoPath = ApplicationUtils.getApplication().getPath(PathType.LIBRARY, "pluginInfo.txt"); + + // Delete Plugin + if (Files.exists(pluginInfoPath)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(pluginInfoPath))); + String line; + while ((line = reader.readLine()) != null) { + Path plugin = Paths.get(line); + Files.deleteIfExists(plugin); + } + reader.close(); + Files.delete(pluginInfoPath); + } + + // Load Plugins + pluginManager = PluginManagerFactory.createPluginManager(); + if (ApplicationUtils.getApplication().isDebug()) + // DEBUG PLUGINS EINBINDEN + pluginManager.addPluginsFrom(Paths.get("/Users/tobias/Documents/Programmieren/Java/eclipse/PlayWallPlugins/bin/").toUri()); + else + pluginManager.addPluginsFrom(ApplicationUtils.getApplication().getPath(PathType.LIBRARY).toUri()); + + // Shutdown Plugins + Runtime.getRuntime().addShutdownHook(new Thread(() -> + { + pluginManager.shutdown(); + + try { + if (Files.notExists(pluginInfoPath)) { + Files.createDirectories(pluginInfoPath.getParent()); + Files.createFile(pluginInfoPath); + } + PrintWriter deleteWriter = new PrintWriter(Files.newOutputStream(pluginInfoPath)); + for (Path path : deletedPlugins) { + deleteWriter.println(path.toString()); + } + deleteWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + })); + } + + private void setupLocalization() { + Localization.setDelegate(this); + Localization.load(); + + uiResourceBundle = Localization.loadBundle("de/tobias/playpad/assets/lang/ui", getClass().getClassLoader()); + } + + public static void launchProject(Project project) { + mainViewController = new MainViewController(project, mainViewListeners, pluginManager); + } + + @Override + public void reloadSettings(Profile oldProfile, Profile currentProfile) { + if (currentProfile.getProfileSettings().isAutoUpdate()) { + Worker.runLater(() -> + { + UpdateRegistery.lookupUpdates(); + if (!UpdateRegistery.getAvailableUpdates().isEmpty()) { + Platform.runLater(() -> + { + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setHeaderText(Localization.getString(Strings.UI_Dialog_AutoUpdate_Header)); + alert.setContentText(Localization.getString(Strings.UI_Dialog_AutoUpdate_Content)); + alert.showAndWait().filter(item -> item == ButtonType.OK).ifPresent(result -> + { + UpdateTabViewController.update(null); + }); + }); + } + }); + } + } + + @Override + public String getBaseResource() { + return "de/tobias/playpad/assets/lang/"; + } + + @Override + public Locale getLocale() { + return Locale.getDefault(); + } + + /* + * Plugins + */ + protected static List<WindowListener<IMainViewController>> mainViewListeners = new ArrayList<>(); + protected static List<WindowListener<ISettingsViewController>> settingsViewListeners = new ArrayList<>(); + protected static List<WindowListener<IPadSettingsViewController>> padSettingsViewListeners = new ArrayList<>(); + protected static List<SettingsListener> settingsListeners = new ArrayList<>(); + protected static List<PadListener> padListeners = new ArrayList<>(); + + @Override + public void addMainViewListener(WindowListener<IMainViewController> listener) { + mainViewListeners.add(listener); + } + + @Override + public void removeMainViewListener(WindowListener<IMainViewController> listener) { + mainViewListeners.remove(listener); + } + + @Override + public void addSettingsViewListener(WindowListener<ISettingsViewController> listener) { + settingsViewListeners.add(listener); + } + + @Override + public void removeSettingsViewListener(WindowListener<ISettingsViewController> listener) { + settingsViewListeners.remove(listener); + } + + @Override + public List<WindowListener<ISettingsViewController>> getSettingsViewListener() { + return settingsViewListeners; + } + + @Override + public void addPadSettingsViewListener(WindowListener<IPadSettingsViewController> listener) { + padSettingsViewListeners.add(listener); + } + + @Override + public void removePadSettingsViewListener(WindowListener<IPadSettingsViewController> listener) { + padSettingsViewListeners.remove(listener); + } + + @Override + public List<WindowListener<IPadSettingsViewController>> getPadSettingsViewListener() { + return padSettingsViewListeners; + } + + @Override + public void addSettingsListener(SettingsListener listener) { + settingsListeners.add(listener); + } + + @Override + public void removeSettingsListener(SettingsListener listener) { + settingsListeners.remove(listener); + } + + @Override + public List<SettingsListener> getSettingsListener() { + return settingsListeners; + } + + @Override + public void addPadListener(PadListener listener) { + padListeners.add(listener); + } + + @Override + public void removePadListener(PadListener listener) { + padListeners.remove(listener); + } + + @Override + public List<PadListener> getPadListener() { + return padListeners; + } + + @Override + public MainViewController getMainViewController() { + return mainViewController; + } + + @Override + public PluginManager getPluginManager() { + return pluginManager; + } + + @Override + public String[] getProjectFiles() { + return projectType; + } + + @Override + public Optional<Image> getIcon() { + return stageIcon; + } + + public static Updatable getUpdater() { + return updater; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/PlayPadUpdater.java b/PlayWall/src/de/tobias/playpad/PlayPadUpdater.java new file mode 100644 index 0000000000000000000000000000000000000000..be17c2fe34175743038c7fd97744c106298ecddc --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/PlayPadUpdater.java @@ -0,0 +1,91 @@ +package de.tobias.playpad; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import de.tobias.utils.application.App; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.util.SystemUtils; + +public class PlayPadUpdater implements Updatable { + + private int newBuild; + private String newVersion; + private URL remotePath; + + @Override + public int getCurrentBuild() { + return (int) ApplicationUtils.getMainApplication().getInfo().getBuild(); + } + + @Override + public String getCurrentVersion() { + return ApplicationUtils.getMainApplication().getInfo().getVersion(); + } + + @Override + public int getNewBuild() { + if (newBuild == 0) { + checkUpdate(); + } + return newBuild; + } + + @Override + public String getNewVersion() { + if (newVersion == null) { + checkUpdate(); + } + return newVersion; + } + + @Override + public boolean checkUpdate() { + App app = ApplicationUtils.getMainApplication(); + try { + FileConfiguration config = YamlConfiguration.loadConfiguration(new URL(app.getInfo().getUpdateURL() + "/version.yml").openStream()); + newBuild = config.getInt("build"); + newVersion = config.getString("version"); + + if (SystemUtils.isExe()) { + remotePath = new URL(config.getString("pathExe")); + } else { + remotePath = new URL(config.getString("pathJar")); + } + + return getCurrentBuild() < getNewBuild(); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public URL getDownloadPath() { + if (remotePath == null) { + checkUpdate(); + } + return remotePath; + } + + @Override + public Path getLocalPath() { + try { + return SystemUtils.getRunPath(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public String name() { + return ApplicationUtils.getApplication().getInfo().getName(); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/PseudoClasses.java b/PlayWall/src/de/tobias/playpad/PseudoClasses.java new file mode 100644 index 0000000000000000000000000000000000000000..0bb01d7339f00d9df02746e900b57ed8a844dc29 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/PseudoClasses.java @@ -0,0 +1,13 @@ +package de.tobias.playpad; + +import javafx.css.PseudoClass; + +public class PseudoClasses { + + public static final PseudoClass ERROR_CLASS = PseudoClass.getPseudoClass("error"); + public static final PseudoClass PLAY_CALSS = PseudoClass.getPseudoClass("play"); + public static final PseudoClass FADE_CLASS = PseudoClass.getPseudoClass("fade"); + public static final PseudoClass WARN_CLASS = PseudoClass.getPseudoClass("warn"); + public static final PseudoClass HOVER_CLASS = PseudoClass.getPseudoClass("drag"); + public static final PseudoClass DRAG_CLASS = PseudoClass.getPseudoClass("drag"); +} diff --git a/PlayWall/src/de/tobias/playpad/Strings.java b/PlayWall/src/de/tobias/playpad/Strings.java new file mode 100644 index 0000000000000000000000000000000000000000..7dae7bef76b698e9dec6f00d12fe3fa15b5e32d2 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/Strings.java @@ -0,0 +1,218 @@ +package de.tobias.playpad; + +public class Strings { + + // Standard - File + public static final String Standard_File_Save = "Standard.File.Save"; + public static final String Standard_Copy = "Standard.Copy"; + public static final String Standard_Time_Seconds = "Standard.Time.Seconds"; + + // File - Filter + public static final String File_Filter_ZIP = "File.Filter.ZIP"; + public static final String File_Filter_Media = "File.Filter.Media"; + public static final String File_Filter_Preset = "File.Filter.Preset"; + + // Timemode - Enum + public static final String Pad_TimeMode_BaseName = "Pad.TimeMode."; + + // UI - Window - Titles + public static final String UI_Dialog_Launch_Title = "UI.Dialog.Launch.Title"; + public static final String UI_Window_Main_Title = "UI.Window.Main.Title"; + public static final String UI_Window_Changelog_Title = "UI.Window.Changelog.Title"; + public static final String UI_Window_Settings_Title = "UI.Window.Settings.Title"; + public static final String UI_Window_PadSettings_Title = "UI.Window.PadSettings.Title"; + public static final String UI_Dialog_DragAndDrop_Title = "UI.Dialog.DragAndDrop.Title"; + public static final String UI_Dialog_ProjectExport_Title = "UI.Dialog.ProjectExport.Title"; + public static final String UI_Dialog_ErrorSummary_Title = "UI.Dialog.ErrorSummary.Title"; + public static final String UI_Dialog_NewProile_Title = "UI.Dialog.NewProfile.Title"; + public static final String UI_Dialog_NewProject_Title = "UI.Dialog.NewProject.Title"; + public static final String UI_Dialog_ChooseProfile_Title = "UI.Dialog.ChooseProfile.Title"; + public static final String UI_Dialog_ProjectManager_Title = "UI.Dialog.ProjectManager.Title"; + public static final String UI_Dialog_UpdateCenter_Title = "UI.Dialog.UpdateCenter.Title"; + public static final String UI_Dialog_Preset_Title = "UI.Dialog.Preset.Title"; + public static final String UI_Dialog_Plugins_Title = "UI.Dialog.Plugins.Title"; + public static final String UI_Dialog_Print_Title = "UI.Dialog.Print.Title"; + public static final String UI_Dialog_Profile_Title = "UI.Dialog.Profile.Title"; + + // UI - Standard + public static final String UI_Standard_DoNotShow = "UI.Standard.DoNotShow"; + + // UI - Layout - Classic - Theme - Enum + public static final String UI_Layout_Classic_Theme_BaseName = "UI.Layout.Classic.Theme."; + + // UI - Window - Main + public static final String UI_Window_Main_CloseRequest = "UI.Window.Main.CloseRequest"; + public static final String UI_Window_Main_PageButton = "UI.Window.Main.PageButton"; + + // UI - Dialog - Launch + public static final String UI_Dialog_Launch_Info = "UI.Dialog.Launch.Info"; + + // UI - Window - Settings + public static final String UI_Window_Settings_Gen_Title = "UI.Window.Settings.Gen.Title"; + public static final String UI_Window_Settings_Gen_CacheSize = "UI.Window.Settings.Gen.CacheSize"; + public static final String UI_Window_Settings_Mapping_Title = "UI.Window.Settings.Mapping.Title"; + public static final String UI_Window_Settings_Midi_Title = "UI.Window.Settings.Midi.Title"; + public static final String UI_Window_Settings_Layout_Title = "UI.Window.Settings.Layout.Title"; + public static final String UI_Window_Settings_Player_Title = "UI.Window.Settings.Player.Title"; + public static final String UI_Window_Settings_Audio_Title = "UI.Window.Settings.Audio.Title"; + public static final String UI_Window_Settings_Updates_Title = "UI.Window.Settings.Updates.Title"; + + // UI - Dialogs - DragAndDrop + public static final String UI_Dialog_DragAndDrop_Header = "UI.Dialog.DragAndDrop.Header"; + public static final String UI_Dialog_DragAndDrop_Content = "UI.Dialog.DragAndDrop.Content"; + public static final String UI_Dialog_DragAndDrop_Button = "UI.Dialog.DragAndDrop.Button"; + + // UI - Dialog - NewProfile + public static final String UI_Dialog_NewProfile_Content = "UI.Dialog.NewProfile.Content"; + + // UI - Dialog - NewProject + public static final String UI_Dialog_NewProject_Content = "UI.Dialog.NewProject.Content"; + + // UI - Dialog - Import + public static final String UI_Dialog_Import_ReplaceProfile_Content = "UI.Dialog.Import.ReplaceProfile.Content"; + public static final String UI_Dialog_Import_ReplaceProfile_Skip = "UI.Dialog.Import.ReplaceProfile.Skip"; + public static final String UI_Dialog_Import_ReplaceProfile_Rename = "UI.Dialog.Import.ReplaceProfile.Rename"; + public static final String UI_Dialog_Import_ReplaceProfile_ReplaceContent = "UI.Dialog.Import.ReplaceProfile.ReplaceContent"; + public static final String UI_Dialog_Import_ReplaceProject_ReplaceContent = "UI.Dialog.Import.ReplaceProject.ReplaceContent"; + public static final String UI_Dialog_Import_ReplaceMedia_Content = "UI.Dialog.Import.ReplaceMedia.Content"; + public static final String UI_Dialog_Import_ReplaceMedia_Copy = "UI.Dialog.Import.ReplaceMedia.Copy"; + public static final String UI_Dialog_Import_ReplaceMedia_Skip = "UI.Dialog.Import.ReplaceMedia.Skip"; + + // UI - Dialog - ProjectManager + public static final String UI_Dialog_ProjectManager_Delete_Content = "UI.Dialog.ProjectManager.Delete.Content"; + + // UI - Dialog - Profile + public static final String UI_Dialog_Profile_Delete_Content = "UI.Dialog.Profile.Delete.Content"; + + // UI - Dialog - Info + public static final String UI_Dialog_Info_Header = "UI.Dialog.Info.Header"; + public static final String UI_Dialog_Info_Content = "UI.Dialog.Info.Content"; + + // UI - Dialog - Feedback + public static final String UI_Dialog_Feedback_Content = "UI.Dialog.Feedback.Content"; + + // UI - Placeholder + public static final String UI_Placeholder_Project = "UI.Placeholder.Project"; + public static final String UI_Placeholder_Preset = "UI.Placeholder.Preset"; + public static final String UI_Placeholder_Plugins = "UI.Placeholder.Plugins"; + public static final String UI_Placeholder_Updates = "UI.Placeholder.Updates"; + public static final String UI_Placeholder_ErrorSummary = "UI.Placeholder.ErrorSummary"; + + // Info - MIDI + public static final String Info_Midi_Device_Connected = "Info.Midi.Device.Connected"; + + // Info - Settings + public static final String Info_Settings_ResetWarning = "Info.Settings.ResetWarning"; + public static final String Info_Settings_CacheDelete = "Info.Settings.CacheDelete"; + + // Info - Print + public static final String Info_Print_Header = "Info.Print.Header"; + + // Error - Standard + public static final String Error_Standard_Gen = "Error.Standard.Gen"; + public static final String Error_Standard_NameInUse = "Error.Standard.NameInUse"; + + // Error - Settings + public static final String Error_Settings_CacheSize = "Error.Settings.CacheSize"; + public static final String Error_Settings_CacheClear = "Error.Settings.CacheClear"; + + // Error - Profile + public static final String Error_Profile_Create = "Error.Profile.Create"; + public static final String Error_Profile_NotFound = "Error.Profile.NotFound"; + public static final String Error_Profile_Save = "Error.Profile.Save"; + public static final String Error_Profile_Delete = "Error.Profile.Delete"; + public static final String Error_Profile_SmallScreen = "Error.Profile.SmallScreen"; + + // Error - Preset + public static final String Error_Preset_Import = "Error.Preset.Import"; + public static final String Error_Preset_Export = "Error.Preset.Export"; + + // Error - Project + public static final String Error_Project_Create = "Error.Project.Create"; + public static final String Error_Project_NotFound = "Error.Project.NotFound"; + public static final String Error_Project_Open = "Error.Project.Open"; + public static final String Error_Project_Save = "Error.Project.Save"; + public static final String Error_Project_Rename = "Error.Project.Rename"; + public static final String Error_Project_Delete = "Error.Project.Delete"; + public static final String Error_Project_Export = "Error.Project.Export"; + + // Error - Pad + public static final String Error_Pad_BaseName = "Error.Pad."; + + // Error - Fix + public static final String Error_Fix_NewFile = "Error.Fix.NewFile"; + + // Error - Midi + public static final String Error_Midi_Settings_Unkown = "Error.Midi.Settings.Unkown"; + public static final String Error_Midi_Device_Busy = "Error.Midi.Device.Busy"; + public static final String Error_Midi_Device_Unavailible = "Error.Midi.Device.Unavailible"; + public static final String Error_Midi_Record_Fail = "Error.Midi.Record.Fail"; + public static final String Error_Midi_Send = "Error.Midi.Send"; + + // Error - Plugins + public static final String Error_Plugins_Download = "Error.Plugins.Download"; + + /* + * NEU + */ + + // Mapper + public static final String Mapper_Keyboard_Name = "Mapper.Keyboard.Name"; + public static final String Mapper_Midi_Name = "Mapper.Midi.Name"; + public static final String Mapper_Keyboard_toString = "Mapper.Keyboard.toString"; + public static final String Mapper_Midi_toString = "Mapper.Midi.toString"; + + // Info - Mapper + public static final String Info_Mapper_PressKey = "Info.Mapper.PressKey"; + + // UI - Window - PadSettings + public static final String UI_Window_PadSettings_General_Title = "UI.Window.PadSettings.General.Title"; + public static final String UI_Window_PadSettings_Player_Title = "UI.Window.PadSettings.Player.Title"; + public static final String UI_Window_PadSettings_Layout_Title = "UI.Window.PadSettings.Layout.Title"; + public static final String UI_Window_PadSettings_Trigger_Title = "UI.Window.PadSettings.Trigger.Title"; + + // Actions + public static final String Action_Cart_toString = "Action.Cart.toString"; + public static final String Action_Page_toString = "Action.Page.toString"; + public static final String Action_Navigate_toString = "Action.Navigate.toString"; + public static final String Action_Cart_Name = "Action.Cart.Name"; + public static final String Action_Page_Name = "Action.Page.Name"; + public static final String Action_Navigate_Name = "Action.Navigate.Name"; + + // Content + public static final String Content_Empty = "Content.Empyt"; + public static final String Content_Audio_Name = "Content.Audio.Name"; + + // NavigationType - Enum + public static final String NavigationType_BaseName = "NavigationType."; + + // ControlMode - Enum + public static final String CartAction_Mode_BaseName = "CartAction.Mode."; + + // UI - Dialog - AutoUpdate + public static final String UI_Dialog_AutoUpdate_Header = "UI.Dialog.AutoUpdate.Header"; + public static final String UI_Dialog_AutoUpdate_Content = "UI.Dialog.AutoUpdate.Content"; + + // Error - Layout + public static final String Error_Layout_Load = "Error.Layout.Load"; + + // UI - Dialog - Update + public static final String UI_Dialog_Update_Cell = "UI.Dialog.Update.Cell"; + public static final String UI_Window_Settings_Updates_CurrentVersion = "UI.Window.Settings.Updates.CurrentVersion"; + public static final String UI_Window_Settings_Updates_NewVersion = "UI.Window.Settings.Updates.NewVersion"; + + // Error - Update - Downlaod + public static final String Error_Update_Download = "Error.Update.Download"; + + // Layout + public static final String Layout_Modern_Name = "Layout.Modern.Name"; + public static final String Layout_Classic_Name = "Layout.Classic.Name"; + + // Trigger + public static final String TriggerPoint_toString = "TriggerPoint.toString"; + public static final String Trigger_Cart_Name = "Trigger.Cart.Name"; + public static final String Trigger_Volume_Name = "Trigger.Volume.Name"; + + // TriggerPoint - Enum + public static final String TriggerPoint_BaseName = "TriggerPoint."; +} diff --git a/PlayWall/src/de/tobias/playpad/VersionUpdater.java b/PlayWall/src/de/tobias/playpad/VersionUpdater.java new file mode 100644 index 0000000000000000000000000000000000000000..183b998e9cd90623b87e27f53430a5a0ced73fc8 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/VersionUpdater.java @@ -0,0 +1,228 @@ +package de.tobias.playpad; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; + +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.cartaction.CartAction.ControlMode; +import de.tobias.playpad.action.feedback.DoubleSimpleFeedback; +import de.tobias.playpad.action.mapper.MidiMapper; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.application.App; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.application.update.UpdateService; + +public class VersionUpdater implements UpdateService { + + @Override + public void update(App app, long oldVersion, long newVersion) { + System.out.println("Update"); + if (oldVersion <= 18) { + SAXReader reader = new SAXReader(); + Path path = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, "Profiles.xml"); + + try { + Document document = reader.read(Files.newInputStream(path)); + Element root = document.getRootElement(); + for (Object object : root.elements("Document")) { + Element element = (Element) object; + String name = element.getStringValue(); + + UUID uuid = UUID.randomUUID(); + + Path projectPath = ApplicationUtils.getApplication().getPath(PathType.DOCUMENTS, name); + Path newProjectPath = ApplicationUtils.getApplication().getPath(PathType.DOCUMENTS, uuid + Project.FILE_EXTENSION); + Files.createDirectories(newProjectPath); + + Files.move(projectPath, newProjectPath); + + ProjectReference projectReference = new ProjectReference(uuid, name, ProfileReference.getProfiles().get(0)); + ProjectReference.addProject(projectReference); + + convertProject(newProjectPath); + } + + ProjectReference.saveProjects(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (oldVersion <= 23) { + System.out.println("Update Data"); + Path configPath = app.getPath(PathType.CONFIGURATION); + SAXReader reader = new SAXReader(); + try { + Document document = reader.read(Files.newInputStream(configPath.resolve("Profiles.xml"))); + for (Object profileObj : document.getRootElement().elements("Profile")) { + if (profileObj instanceof Element) { + String name = ((Element) profileObj).getStringValue(); + System.out.println("Start Profile: " + name); + UUID uuid = UUID.randomUUID(); + + Path profileOldPath = app.getPath(PathType.CONFIGURATION, name); + Path profileNewPath = app.getPath(PathType.CONFIGURATION, uuid.toString()); + + Files.move(profileOldPath, profileNewPath); + + convertMidiToMapping(profileNewPath); + + ProfileReference profileReference = new ProfileReference(uuid, name); + ProfileReference.addProfile(profileReference); + System.out.println("Finish Profile: " + name + " (" + uuid + ")"); + } + } + } catch (DocumentException | IOException e1) { + e1.printStackTrace(); + } + + try { + Document document = reader.read(Files.newInputStream(configPath.resolve("Projects.xml"))); + for (Object projectObj : document.getRootElement().elements("Project")) { + if (projectObj instanceof Element) { + try { + String name = ((Element) projectObj).getStringValue(); + Path projectPath = app.getPath(PathType.DOCUMENTS, name); + System.out.println("Start Project: " + projectPath); + + UUID uuid = UUID.randomUUID(); + Path newProjectPath = ApplicationUtils.getApplication().getPath(PathType.DOCUMENTS, uuid + Project.FILE_EXTENSION); + + Files.move(projectPath, newProjectPath); + + ProjectReference projectReference = new ProjectReference(uuid, projectPath.getFileName().toString(), + ProfileReference.getProfiles().get(0)); + ProjectReference.addProject(projectReference); + + convertProject(newProjectPath); + System.out.println("End Project: " + projectPath + " (" + uuid + ")"); + } catch (DocumentException | URISyntaxException e) { + e.printStackTrace(); + } + } + } + } catch (IOException | DocumentException e) { + e.printStackTrace(); + } + try { + ProfileReference.saveProfiles(); + ProjectReference.saveProjects(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void convertMidiToMapping(Path configPath) throws DocumentException, IOException { + SAXReader reader = new SAXReader(); + Document midiDocument = reader.read(Files.newInputStream(configPath.resolve("Midi.xml"))); + + List<Mapping> mappings = new ArrayList<>(); + + for (Object presetObj : midiDocument.getRootElement().elements("Preset")) { + Element presetElement = (Element) presetObj; + String name = presetElement.attributeValue("name"); + + Mapping mapping = new Mapping(false, null); + mapping.setName(name); + mapping.setUuid(UUID.randomUUID()); + + for (Object midiObj : presetElement.elements("Midi")) { + Element midiElement = (Element) midiObj; + int command = Integer.valueOf(midiElement.attributeValue("command")); + int key = Integer.valueOf(midiElement.attributeValue("channel")); + + if (midiElement.attributeValue("type") != null) { + if (midiElement.attributeValue("type").equals("de.tobias.playpad.model.midi.type.PlayStopActionType")) { + Element actionElement = midiElement.element("Action"); + if (actionElement.attributeValue("class").equals("de.tobias.playpad.model.midi.CartAction")) { + int cart = Integer.valueOf(actionElement.element("CartID").getStringValue()); + + CartAction action = new CartAction(cart, ControlMode.PLAY_STOP); + mapping.addActionIfNotContains(action); + + MidiMapper mapper = new MidiMapper(command, key); + action.addMapper(mapper); + + Element feedbackEventElement = actionElement.element("Feedback"); + Element feedbackDefaultElement = midiElement.element("Feedback"); + + int feedbackEvent = Integer.valueOf(feedbackEventElement.element("MidiVelocity").getStringValue()); + int feedbackDefault = Integer.valueOf(feedbackDefaultElement.element("MidiVelocity").getStringValue()); + + DoubleSimpleFeedback doubleSimpleFeedback = new DoubleSimpleFeedback(feedbackDefault, feedbackEvent); + mapper.setFeedback(doubleSimpleFeedback); + } + } + } + } + mappings.add(mapping); + } + + Document mappingDocument = DocumentHelper.createDocument(); + Element rootElement = mappingDocument.addElement("List"); + + for (Mapping mapping : mappings) { + Element mappingElement = rootElement.addElement("Mapping"); + mapping.save(mappingElement); + } + + XMLWriter writer = new XMLWriter(Files.newOutputStream(configPath.resolve("Mapping.xml")), OutputFormat.createPrettyPrint()); + writer.write(mappingDocument); + writer.close(); + + Files.delete(configPath.resolve("Midi.xml")); + } + + public void convertProject(Path path) throws DocumentException, IOException, URISyntaxException { + SAXReader reader = new SAXReader(); + Document oldDocument = reader.read(Files.newInputStream(path)); + Document newDocument = DocumentHelper.createDocument(); + + Element newRootElement = newDocument.addElement("Project"); + + for (Object oldPadObj : oldDocument.getRootElement().elements("Pad")) { + try { + Element oldPadElement = (Element) oldPadObj; + Element newPadElement = newRootElement.addElement("Pad"); + + newPadElement.addAttribute("index", oldPadElement.attributeValue("index")); + newPadElement.addAttribute("name", oldPadElement.element("Title").getStringValue()); + newPadElement.addAttribute("status", oldPadElement.element("State").getStringValue()); + + String file = oldPadElement.element("Path").getStringValue(); + URI uri = new URI(file); + newPadElement.addElement("Content").addAttribute("type", "audio").addText(Paths.get(uri).toString()); + + Element newSettingsElement = newPadElement.addElement("Settings"); + newSettingsElement.addElement("Volume").addText(oldPadElement.element("Volume").getStringValue()); + newSettingsElement.addElement("Loop").addText(oldPadElement.element("Loop").getStringValue()); + if (oldPadElement.element("TimeMode") != null) + newSettingsElement.addElement("TimeMode").addText(oldPadElement.element("TimeMode").getStringValue()); + } catch (Exception e) {} + } + + XMLWriter writer = new XMLWriter(Files.newOutputStream(path), OutputFormat.createPrettyPrint()); + writer.write(newDocument); + writer.close(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/MappingUtils.java b/PlayWall/src/de/tobias/playpad/action/MappingUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..a455969b8ec932bff1cc255c43a8c0e8784e1753 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/MappingUtils.java @@ -0,0 +1,42 @@ +package de.tobias.playpad.action; + +import java.util.ArrayList; +import java.util.List; + +import de.tobias.playpad.action.mapper.KeyboardMapper; +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MidiMapper; +import javafx.scene.input.KeyCode; + +public class MappingUtils { + + public static List<Action> getActionsForKey(KeyCode code, Mapping mapping) { + List<Action> actions = new ArrayList<>(); + for (Action action : mapping.keySet()) { + for (Mapper mapper : mapping.get(action)) { + if (mapper instanceof KeyboardMapper) { + KeyboardMapper keyMapper = (KeyboardMapper) mapper; + if (keyMapper.getCode() == code) { + actions.add(action); + } + } + } + } + return actions; + } + + public static List<Action> getActionsForMidi(int cmd, int key, Mapping mapping) { + List<Action> actions = new ArrayList<>(); + for (Action action : mapping.keySet()) { + for (Mapper mapper : mapping.get(action)) { + if (mapper instanceof MidiMapper) { + MidiMapper midiMapper = (MidiMapper) mapper; + if (midiMapper.getCommand() == cmd && midiMapper.getKey() == key) { + actions.add(action); + } + } + } + } + return actions; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/actions/NavigateAction.java b/PlayWall/src/de/tobias/playpad/action/actions/NavigateAction.java new file mode 100644 index 0000000000000000000000000000000000000000..b4c9e005d4ad67297301d689e39bef045c7d9ab6 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/actions/NavigateAction.java @@ -0,0 +1,121 @@ +package de.tobias.playpad.action.actions; + +import org.dom4j.Element; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.InputType; +import de.tobias.playpad.action.connect.NavigateActionConnect; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.feedback.FeedbackType; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class NavigateAction extends Action { + + public enum NavigationType { + PREVIOUS, + NEXT; + + public String toString() { + return Localization.getString(Strings.NavigationType_BaseName + name()); + }; + } + + private NavigationType action; + + public NavigateAction() { + action = NavigationType.NEXT; + } + + public NavigateAction(NavigationType type) { + this.action = type; + } + + public NavigationType getAction() { + return action; + } + + public void setAction(NavigationType action) { + this.action = action; + } + + @Override + public String getType() { + return NavigateActionConnect.TYPE; + } + + @Override + public void initFeedback(Project project, IMainViewController controller) { + handleFeedback(FeedbackMessage.STANDARD); + } + + @Override + public void clearFeedback() { + handleFeedback(FeedbackMessage.OFF); + } + + @Override + public void performAction(InputType type, Project project, IMainViewController mainViewController) { + if (type == InputType.PRESSED) { + switch (this.action) { + case PREVIOUS: + Platform.runLater(() -> mainViewController.showPage(mainViewController.getPage() - 1)); + break; + case NEXT: + Platform.runLater(() -> mainViewController.showPage(mainViewController.getPage() + 1)); + break; + default: + break; + } + } + } + + @Override + public FeedbackType geFeedbackType() { + return FeedbackType.SINGLE; + } + + private static final String TYPE = "action"; + + @Override + public void load(Element root) { + action = NavigationType.valueOf(root.attributeValue(TYPE)); + } + + @Override + public void save(Element root) { + root.addAttribute(TYPE, action.name()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NavigateAction) { + return ((NavigateAction) obj).getAction() == action; + } + return super.equals(obj); + } + + @Override + public String toString() { + return Localization.getString(Strings.Action_Navigate_toString, action.toString()); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(toString()); + } + + @Override + public Action cloneAction() throws CloneNotSupportedException { + NavigateAction actionClone = (NavigateAction) super.clone(); + + actionClone.action = this.action; + + return actionClone; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/actions/PageAction.java b/PlayWall/src/de/tobias/playpad/action/actions/PageAction.java new file mode 100644 index 0000000000000000000000000000000000000000..6cc149eb532554103b8b7f3b1badf41ab10b11f3 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/actions/PageAction.java @@ -0,0 +1,108 @@ +package de.tobias.playpad.action.actions; + +import org.dom4j.Element; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.InputType; +import de.tobias.playpad.action.connect.PageActionConnect; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.feedback.FeedbackType; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class PageAction extends Action { + + private int page; + + public PageAction() { + this.page = 0; + } + + public PageAction(int page) { + super(); + this.page = page; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } + + @Override + public String getType() { + return PageActionConnect.TYPE; + } + + @Override + public void initFeedback(Project project, IMainViewController controller) { + int page = controller.getPage(); + if (page == this.page) { + handleFeedback(FeedbackMessage.EVENT); + } else { + handleFeedback(FeedbackMessage.STANDARD); + } + } + + @Override + public void clearFeedback() { + handleFeedback(FeedbackMessage.OFF); + } + + @Override + public void performAction(InputType type, Project project, IMainViewController mainViewController) { + if (type == InputType.PRESSED) { + Platform.runLater(() -> mainViewController.showPage(page)); + } + } + + @Override + public FeedbackType geFeedbackType() { + return FeedbackType.DOUBLE; + } + + private static final String PAGE = "page"; + + @Override + public void load(Element root) { + page = Integer.valueOf(root.attributeValue(PAGE)); + } + + @Override + public void save(Element root) { + root.addAttribute(PAGE, String.valueOf(page)); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PageAction) { + return ((PageAction) obj).getPage() == page; + } + return super.equals(obj); + } + + @Override + public String toString() { + return Localization.getString(Strings.Action_Page_toString, String.valueOf(page + 1)); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(toString()); + } + + public Action cloneAction() throws CloneNotSupportedException { + PageAction action = (PageAction) super.clone(); + + action.page = page; + + return action; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java b/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java new file mode 100644 index 0000000000000000000000000000000000000000..5dd5cf62b8df9d6766281d5ab0a85ce8dcb0531c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java @@ -0,0 +1,254 @@ +package de.tobias.playpad.action.cartaction; + +import org.dom4j.Element; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.InputType; +import de.tobias.playpad.action.connect.CartActionConnect; +import de.tobias.playpad.action.feedback.FeedbackType; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.viewcontroller.actions.CartActionViewController; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class CartAction extends Action { + + public enum ControlMode { + PLAY_PAUSE, + PLAY_STOP, + PLAY_HOLD; + } + + private int cart; + private ControlMode mode; + private boolean autoFeedbackColors; + + private transient Pad pad; + private transient PadStatusFeedbackListener padStatusFeedbackListener = new PadStatusFeedbackListener(); + private transient PadPositionWarningListener padPositionListener = new PadPositionWarningListener(this); + + public CartAction() { + this.cart = 0; + this.mode = ControlMode.PLAY_STOP; + this.autoFeedbackColors = true; + } + + public CartAction(int cart, ControlMode mode) { + this.cart = cart; + this.mode = mode; + this.autoFeedbackColors = true; + } + + public int getCart() { + return cart; + } + + public void setCart(int cart) { + this.cart = cart; + } + + public ControlMode getMode() { + return mode; + } + + public void setMode(ControlMode mode) { + this.mode = mode; + } + + public boolean isAutoFeedbackColors() { + return autoFeedbackColors; + } + + public void setAutoFeedbackColors(boolean autoFeedbackColors) { + this.autoFeedbackColors = autoFeedbackColors; + } + + // Helper + public Pad getPad() { + return pad; + } + + @Override + public void initFeedback(Project project, IMainViewController controller) { + Pad pad = project.getPad(cart); + setPad(pad); + // init first feedback + padStatusFeedbackListener.changed(null, null, pad.getStatus()); + } + + @Override + public void clearFeedback() { + setPad(null); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CartAction) { + CartAction action2 = (CartAction) obj; + if (action2.cart == cart) { + return true; + } + } + return super.equals(obj); + } + + @Override + public String getType() { + return CartActionConnect.TYPE; + } + + @Override + public void performAction(InputType type, Project project, IMainViewController mainViewController) { + setPad(project.getPad(cart)); + + // wird nur ausgeführt, wenn das Pad ein Content hat und sichtbar in der GUI (Gilt für MIDI und Keyboard) + if (pad.getContent() != null && pad.getContent().isPadLoaded() && pad.isPadVisible()) { + switch (mode) { + case PLAY_STOP: + if (type == InputType.PRESSED) { + if (pad.getStatus() == PadStatus.PLAY) { + pad.setStatus(PadStatus.STOP); + } else { + // Allow the listener to send the feedback + padPositionListener.setSend(false); + + pad.setStatus(PadStatus.PLAY); + } + } + break; + case PLAY_HOLD: + if (type == InputType.PRESSED) { + if (pad.getStatus() == PadStatus.READY) { + // Allow the listener to send the feedback + padPositionListener.setSend(false); + + pad.setStatus(PadStatus.PLAY); + } + } else if (type == InputType.RELEASED) { + if (pad.getStatus() == PadStatus.PLAY) { + pad.setStatus(PadStatus.STOP); + } + } + break; + case PLAY_PAUSE: + if (type == InputType.PRESSED) { + if (pad.getStatus() == PadStatus.PLAY) { + pad.setStatus(PadStatus.PAUSE); + } else { + // Allow the listener to send the feedback + padPositionListener.setSend(false); + + pad.setStatus(PadStatus.PLAY); + } + } + break; + default: + break; + } + } + } + + @Override + public FeedbackType geFeedbackType() { + return FeedbackType.DOUBLE; + } + + private static final String CART_ID = "id"; + private static final String CONTROL_MDOE = "mode"; + private static final String AUTO_FEEDBACK_COLORS = "autoColor"; + + @Override + public void load(Element root) { + cart = Integer.valueOf(root.attributeValue(CART_ID)); + mode = ControlMode.valueOf(root.attributeValue(CONTROL_MDOE)); + autoFeedbackColors = Boolean.valueOf(root.attributeValue(AUTO_FEEDBACK_COLORS)); + } + + @Override + public void save(Element root) { + root.addAttribute(CART_ID, String.valueOf(cart)); + root.addAttribute(CONTROL_MDOE, mode.name()); + root.addAttribute(AUTO_FEEDBACK_COLORS, String.valueOf(autoFeedbackColors)); + } + + public void setPad(Pad newPad) { + Pad oldPad = this.pad; + if (newPad == null || !newPad.equals(oldPad) || oldPad == null) { + // Remove old Listener + if (oldPad != null) { + if (oldPad.getContent() != null) { + if (oldPad.getContent() instanceof Durationable) { + Durationable durationable = (Durationable) oldPad.getContent(); + durationable.positionProperty().removeListener(padPositionListener); + } + } + oldPad.statusProperty().removeListener(padStatusFeedbackListener); + } + + this.pad = newPad; + + if (newPad != null) { + // Add new listener + if (newPad.getContent() != null) { + if (newPad.getContent() instanceof Durationable) { + padPositionListener.setPad(newPad); + Durationable durationable = (Durationable) newPad.getContent(); + durationable.positionProperty().addListener(padPositionListener); + } + } + padStatusFeedbackListener.setAction(this); + newPad.statusProperty().addListener(padStatusFeedbackListener); + } + } + } + + // Listener + public PadPositionWarningListener getPadPositionListener() { + return padPositionListener; + } + + public PadStatusFeedbackListener getPadStatusFeedbackListener() { + return padStatusFeedbackListener; + } + + // Helper + @Override + public Action cloneAction() throws CloneNotSupportedException { + CartAction action = (CartAction) super.clone(); + + action.autoFeedbackColors = autoFeedbackColors; + action.cart = cart; + action.mode = mode; + + return action; + } + + // UI Helper + @Override + public String toString() { + return Localization.getString(Strings.Action_Cart_toString, String.valueOf(cart + 1)); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(toString()); + } + + private static CartActionViewController cartActionViewController; + + @Override + public ContentViewController getSettingsViewController() { + if (cartActionViewController == null) { + cartActionViewController = new CartActionViewController(); + } + cartActionViewController.setCartAction(this); + return cartActionViewController; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/cartaction/PadPositionWarningListener.java b/PlayWall/src/de/tobias/playpad/action/cartaction/PadPositionWarningListener.java new file mode 100644 index 0000000000000000000000000000000000000000..65f551b6321c8e46fa49d35b40072c15239f6f3c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/cartaction/PadPositionWarningListener.java @@ -0,0 +1,56 @@ +package de.tobias.playpad.action.cartaction; + +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.conntent.Durationable; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +public class PadPositionWarningListener implements ChangeListener<Duration> { + + private Pad pad; + private CartAction action; + + boolean send = false; + + public PadPositionWarningListener(CartAction action) { + this.action = action; + } + + public void setPad(Pad pad) { + this.pad = pad; + } + + @Override + public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { + // Nur wenn Pad Sichtbar ist + if (pad != null && pad.isPadVisible()) { + if (pad.getContent() instanceof Durationable) { + Durationable durationable = (Durationable) pad.getContent(); + + // Warning nur wenn kein Loop + if (!pad.isLoop()) { + // Warning + Warning warning = pad.getWarning(); + Duration totalDuration = durationable.getDuration(); + if (totalDuration != null) { + Duration rest = totalDuration.subtract(newValue); + double seconds = rest.toSeconds(); + + if (warning.getTime().toSeconds() > seconds && !send) { + action.handleFeedback(FeedbackMessage.WARNING); + } + send = true; + } + } + } + } + } + + public void setSend(boolean send) { + this.send = send; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/action/cartaction/PadStatusFeedbackListener.java b/PlayWall/src/de/tobias/playpad/action/cartaction/PadStatusFeedbackListener.java new file mode 100644 index 0000000000000000000000000000000000000000..63510122a06d136e3e4553a2866429fea6050bab --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/cartaction/PadStatusFeedbackListener.java @@ -0,0 +1,64 @@ +package de.tobias.playpad.action.cartaction; + +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.Warning; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +public class PadStatusFeedbackListener implements ChangeListener<PadStatus> { + + private CartAction action; + + public void setAction(CartAction action) { + this.action = action; + } + + @Override + public void changed(ObservableValue<? extends PadStatus> observable, PadStatus oldValue, PadStatus newValue) { + if (action != null) { + Pad pad = action.getPad(); + if (pad.isPadVisible()) { + switch (newValue) { + case EMPTY: case ERROR: + action.handleFeedback(FeedbackMessage.OFF); + break; + case PAUSE: + action.handleFeedback(FeedbackMessage.STANDARD); + break; + case PLAY: + action.handleFeedback(FeedbackMessage.EVENT); + + // Wenn Cart in Warning Zeitbereich und vomn Pause zu Play wechselt + try { + if (pad.getContent() instanceof Durationable) { + Durationable durationable = (Durationable) pad.getContent(); + if (!pad.isLoop()) { + Warning warning = pad.getWarning(); + Duration rest = durationable.getDuration().subtract(durationable.getPosition()); + double seconds = rest.toSeconds(); + + if (warning.getTime().toSeconds() > seconds) { + action.handleFeedback(FeedbackMessage.WARNING); + } + } + } + } catch (Exception e) {} + break; + case READY: + action.handleFeedback(FeedbackMessage.STANDARD); + break; + case STOP: + action.handleFeedback(FeedbackMessage.STANDARD); + break; + default: + break; + + } + } + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/connect/CartActionConnect.java b/PlayWall/src/de/tobias/playpad/action/connect/CartActionConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..6ceffddd45ab3f71657482af6db248b1deaa623f --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/connect/CartActionConnect.java @@ -0,0 +1,78 @@ +package de.tobias.playpad.action.connect; + +import java.util.List; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.ActionConnect; +import de.tobias.playpad.action.ActionDisplayable; +import de.tobias.playpad.action.ActionType; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.cartaction.CartAction.ControlMode; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.IMappingTabViewController; +import de.tobias.playpad.viewcontroller.actions.CartActionsViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; +import javafx.scene.control.TreeItem; + +public class CartActionConnect extends ActionConnect implements ActionDisplayable { + + public static final String TYPE = "CART"; + + @Override + public TreeItem<ActionDisplayable> getTreeViewForActions(List<Action> actions, Mapping mapping) { + TreeItem<ActionDisplayable> rootItem = new TreeItem<>(this); + return rootItem; + } + + @Override + public void initActionType(Mapping mapping, Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + int pads = profileSettings.getColumns() * profileSettings.getRows() * profileSettings.getPageCount(); + + for (int i = 0; i < pads; i++) { + CartAction action = new CartAction(i, ControlMode.PLAY_STOP); + mapping.addActionIfNotContains(action); + } + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Action_Cart_Name)); + } + + @Override + public Node getGraphics() { + return new FontIcon(FontAwesomeType.TH); + } + + // Settings View (Übersicht mit den Buttons). Die Buttons rufen dann die jeweilige CartAction auf. Da muss dann auch die MapperView + // manuell gesetzt werden. + @Override + public ContentViewController getActionSettingsViewController(Mapping mapping, IMappingTabViewController controller) { + return new CartActionsViewController(mapping, controller); + } + + @Override + public Action newInstance() { + return new CartAction(); + } + + @Override + public ActionType geActionType() { + return ActionType.CONTROL; + } + + @Override + public String getType() { + return TYPE; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/connect/NavigateActionConnect.java b/PlayWall/src/de/tobias/playpad/action/connect/NavigateActionConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..43c8993ad95b68351a98cd8bf7e8acea2a96cfb0 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/connect/NavigateActionConnect.java @@ -0,0 +1,85 @@ +package de.tobias.playpad.action.connect; + +import java.util.Collections; +import java.util.List; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.ActionConnect; +import de.tobias.playpad.action.ActionDisplayable; +import de.tobias.playpad.action.ActionType; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.actions.NavigateAction; +import de.tobias.playpad.action.actions.NavigateAction.NavigationType; +import de.tobias.playpad.settings.Profile; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.ui.icon.MaterialDesignIcon; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; +import javafx.scene.control.TreeItem; + +public class NavigateActionConnect extends ActionConnect implements ActionDisplayable { + + public static final String TYPE = "NAVIGATE"; + + @Override + public TreeItem<ActionDisplayable> getTreeViewForActions(List<Action> actions, Mapping mapping) { + TreeItem<ActionDisplayable> rootItem = new TreeItem<>(this); + + Collections.sort(actions, (o1, o2) -> + { + if (o1 instanceof NavigateAction && o2 instanceof NavigateAction) { + NavigateAction c1 = (NavigateAction) o1; + NavigateAction c2 = (NavigateAction) o2; + return Long.compare(c1.getAction().ordinal(), c2.getAction().ordinal()); + } else { + return -1; + } + }); + + for (Action action : actions) { + TreeItem<ActionDisplayable> actionItem = new TreeItem<>(action); + rootItem.getChildren().add(actionItem); + } + return rootItem; + } + + @Override + public void initActionType(Mapping mapping, Profile profile) { + mapping.addActionIfNotContains(new NavigateAction(NavigationType.PREVIOUS)); + mapping.addActionIfNotContains(new NavigateAction(NavigationType.NEXT)); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Action_Navigate_Name)); + } + + @Override + public Node getGraphics() { + return new FontIcon(MaterialDesignIcon.FONT_FILE, MaterialDesignIcon.NAVIGATION); + } + + @Override + public ContentViewController getSettingsViewController() { + return null; + } + + @Override + public Action newInstance() { + return new NavigateAction(); + } + + @Override + public ActionType geActionType() { + return ActionType.CONTROL; + } + + @Override + public String getType() { + return TYPE; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/connect/PageActionConnect.java b/PlayWall/src/de/tobias/playpad/action/connect/PageActionConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..7323dca268b9da3fb05725de777c13f833ba21ec --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/connect/PageActionConnect.java @@ -0,0 +1,90 @@ +package de.tobias.playpad.action.connect; + +import java.util.Collections; +import java.util.List; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.ActionConnect; +import de.tobias.playpad.action.ActionDisplayable; +import de.tobias.playpad.action.ActionType; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.actions.PageAction; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; +import javafx.scene.control.TreeItem; + +public class PageActionConnect extends ActionConnect implements ActionDisplayable { + + public static final String TYPE = "PAGE"; + + @Override + public TreeItem<ActionDisplayable> getTreeViewForActions(List<Action> actions, Mapping mapping) { + TreeItem<ActionDisplayable> rootItem = new TreeItem<>(this); + + Collections.sort(actions, (o1, o2) -> + { + if (o1 instanceof PageAction && o2 instanceof PageAction) { + PageAction c1 = (PageAction) o1; + PageAction c2 = (PageAction) o2; + return Long.compare(c1.getPage(), c2.getPage()); + } else { + return -1; + } + }); + + for (Action action : actions) { + TreeItem<ActionDisplayable> actionItem = new TreeItem<>(action); + rootItem.getChildren().add(actionItem); + } + + return rootItem; + } + + @Override + public void initActionType(Mapping mapping, Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + int pages = profileSettings.getPageCount(); + for (int i = 0; i < pages; i++) { + PageAction action = new PageAction(i); + mapping.addActionIfNotContains(action); + } + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Action_Page_Name)); + } + + @Override + public Node getGraphics() { + return new FontIcon(FontAwesomeType.FILE_TEXT); + } + + @Override + public ContentViewController getSettingsViewController() { + return null; + } + + @Override + public Action newInstance() { + return new PageAction(); + } + + @Override + public ActionType geActionType() { + return ActionType.CONTROL; + } + + @Override + public String getType() { + return TYPE; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapper.java b/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4777e9ef78d5aaf08b4e5b9e999a49e2ab6626ba --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapper.java @@ -0,0 +1,120 @@ +package de.tobias.playpad.action.mapper; + +import org.dom4j.Element; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.viewcontroller.mapper.KeyboardMapperViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.StringUtils; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.input.KeyCode; + +public class KeyboardMapper extends Mapper { + + private KeyCode code; + private String key; + + public KeyboardMapper() { + this.code = KeyCode.A; + this.key = "A"; + updateDisplayProperty(); + } + + public KeyboardMapper(KeyCode code, String key) { + this.code = code; + this.key = key; + updateDisplayProperty(); + } + + public KeyCode getCode() { + return code; + } + + public void setCode(KeyCode code) { + this.code = code; + updateDisplayProperty(); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + updateDisplayProperty(); + } + + @Override + public String getType() { + return KeyboardMapperConnect.TYPE; + } + + public String getReadableName() { + if (!StringUtils.isStringNotVisable(getKey())) { + return getKey(); + } else { + return getCode().getName(); + } + } + + // Not Used for Keyboards + @Override + protected void initFeedback() {} + + private static final String KEY = "key"; + private static final String CODE = "code"; + + @Override + public void load(Element element, Action action) { + key = element.attributeValue(KEY); + code = KeyCode.valueOf(element.attributeValue(CODE)); + } + + @Override + public void save(Element element, Action action) { + element.addAttribute(KEY, key); + element.addAttribute(CODE, code.name()); + } + + @Override + public String toString() { + return Localization.getString(Strings.Mapper_Keyboard_toString, getReadableName()); + } + + private StringProperty displayProperty = new SimpleStringProperty(); + + @Override + public StringProperty displayProperty() { + updateDisplayProperty(); + return displayProperty; + } + + private void updateDisplayProperty() { + displayProperty.set(toString()); + } + + private KeyboardMapperViewController settingsViewController; + + @Override + public ContentViewController getSettingsViewController() { + if (settingsViewController == null) { + settingsViewController = new KeyboardMapperViewController(); + } + settingsViewController.setMapper(this); + return settingsViewController; + } + + @Override + public Mapper cloneMapper() throws CloneNotSupportedException { + KeyboardMapper mapper = (KeyboardMapper) super.clone(); + + mapper.code = code; + mapper.key = key; + mapper.displayProperty = new SimpleStringProperty(); + + return mapper; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapperConnect.java b/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapperConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..89bec3547663841b401e36f5101152151a38aa6b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/KeyboardMapperConnect.java @@ -0,0 +1,29 @@ +package de.tobias.playpad.action.mapper; + +import de.tobias.playpad.Strings; +import de.tobias.utils.util.Localization; + +public class KeyboardMapperConnect extends MapperConnect { + + public static final String TYPE = "KEYBOARD"; + + @Override + public MapperViewController getQuickSettingsViewController(Mapper mapper) { + return null; + } + + @Override + public Mapper createNewMapper() { + return new KeyboardMapper(); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public String toString() { + return Localization.getString(Strings.Mapper_Keyboard_Name); + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapper.java b/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..7cc2b7e3b2d70465dc1e894b82fe269826c83a4b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapper.java @@ -0,0 +1,225 @@ +package de.tobias.playpad.action.mapper; + +import java.util.Optional; + +import org.dom4j.Element; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.feedback.ColorAssociator; +import de.tobias.playpad.action.feedback.DisplayableFeedbackColor; +import de.tobias.playpad.action.feedback.DoubleSimpleFeedback; +import de.tobias.playpad.action.feedback.Feedback; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.feedback.FeedbackType; +import de.tobias.playpad.action.feedback.SingleSimpleFeedback; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.action.mididevice.DeviceColorAssociatorConnector; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.viewcontroller.mapper.MidiMapperViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class MidiMapper extends Mapper implements ColorAssociator, MapperFeedbackable { + + private int command; + private int key; + + private Feedback feedback; + private FeedbackType feedbackType; + + public MidiMapper() { + this.command = 0; + this.key = 0; + + updateDisplayProperty(); + } + + public MidiMapper(int command, int key) { + this.command = command; + this.key = key; + updateDisplayProperty(); + } + + public int getCommand() { + return command; + } + + public void setCommand(int command) { + this.command = command; + updateDisplayProperty(); + } + + public int getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + updateDisplayProperty(); + } + + @Override + protected void initFeedback() { + if (feedback == null || this.feedbackType != super.feedbackType) { + if (super.feedbackType == FeedbackType.SINGLE) { + feedback = new SingleSimpleFeedback(); + } else if (super.feedbackType == FeedbackType.DOUBLE) { + feedback = new DoubleSimpleFeedback(); + } + } + this.feedbackType = super.feedbackType; + } + + public Feedback getFeedback() { + return feedback; + } + + public void setFeedback(Feedback feedback) { + this.feedback = feedback; + } + + @Override + public void handleFeedback(FeedbackMessage type) { + Midi.getInstance().getMidiDevice().ifPresent(device -> device.handleFeedback(type, key, feedback)); + } + + @Override + public String getType() { + return MidiMapperConnect.TYPE; + } + + // Feedback, abhängig vom Device + @Override + public boolean supportFeedback() { + Optional<Device> midiDevice = Midi.getInstance().getMidiDevice(); + if (midiDevice.isPresent()) { + return midiDevice.get().supportFeedback(); + } + return false; + } + + @Override + public void setColor(FeedbackMessage feedbackMessage, int value) { + if (feedbackMessage == FeedbackMessage.STANDARD || feedbackMessage == FeedbackMessage.EVENT) { + feedback.setFeedback(feedbackMessage, value); + } else { + throw new IllegalArgumentException("Unexpected Message Type."); + } + } + + @Override + public DisplayableFeedbackColor[] getColors() { + Optional<Device> midiDevice = Midi.getInstance().getMidiDevice(); + if (midiDevice.isPresent()) { + Device device = midiDevice.get(); + if (device instanceof DeviceColorAssociatorConnector) { + return ((DeviceColorAssociatorConnector) device).getColors(); + } + } + return null; + } + + @Override + public DisplayableFeedbackColor getDefaultEventColor() { + Optional<Device> midiDevice = Midi.getInstance().getMidiDevice(); + if (midiDevice.isPresent()) { + Device device = midiDevice.get(); + if (device instanceof DeviceColorAssociatorConnector) { + return ((DeviceColorAssociatorConnector) device).getDefaultEventColor(); + } + } + return null; + } + + @Override + public DisplayableFeedbackColor getDefaultStandardColor() { + Optional<Device> midiDevice = Midi.getInstance().getMidiDevice(); + if (midiDevice.isPresent()) { + Device device = midiDevice.get(); + if (device instanceof DeviceColorAssociatorConnector) { + return ((DeviceColorAssociatorConnector) device).getDefaultStandardColor(); + } + } + return null; + } + + private static final String MIDI_COMMAND = "command"; + private static final String MIDI_KEY = "key"; + private static final String FEEDBACK = "Feedback"; + + @Override + public void load(Element element, Action action) { + String commandValue = element.attributeValue(MIDI_COMMAND); + String keyValue = element.attributeValue(MIDI_KEY); + + if (commandValue != null) { + command = Integer.valueOf(commandValue); + } + if (keyValue != null) { + key = Integer.valueOf(keyValue); + } + + Element feedbackElement = element.element(FEEDBACK); + setFeedbackType(action.geFeedbackType()); + if (feedback != null) { + feedback.load(feedbackElement); + } else { + initFeedback(); + } + } + + @Override + public void save(Element element, Action action) { + element.addAttribute(MIDI_COMMAND, String.valueOf(command)); + element.addAttribute(MIDI_KEY, String.valueOf(key)); + + Element feedbackElement = element.addElement(FEEDBACK); + if (feedback != null) { + feedback.save(feedbackElement); + } + } + + @Override + public String toString() { + return Localization.getString(Strings.Mapper_Midi_toString, key); + } + + private StringProperty displayProperty = new SimpleStringProperty(); + + @Override + public StringProperty displayProperty() { + updateDisplayProperty(); + return displayProperty; + } + + private MidiMapperViewController settingsViewController; + + @Override + public ContentViewController getSettingsViewController() { + if (settingsViewController == null) { + settingsViewController = new MidiMapperViewController(); + } + settingsViewController.setMapper(this); + return settingsViewController; + } + + private void updateDisplayProperty() { + displayProperty.set(toString()); + } + + @Override + public Mapper cloneMapper() throws CloneNotSupportedException { + MidiMapper mapper = (MidiMapper) super.clone(); + + mapper.command = command; + mapper.feedback = feedback.cloneFeedback(); + mapper.key = key; + + mapper.displayProperty = new SimpleStringProperty(); + + return mapper; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapperConnect.java b/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapperConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..f9f169dd42791b3c686c9656ad5056ca0c6098fe --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/MidiMapperConnect.java @@ -0,0 +1,40 @@ +package de.tobias.playpad.action.mapper; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.midi.Midi; +import de.tobias.utils.util.Localization; + +public class MidiMapperConnect extends MapperConnect implements MapperConnectFeedbackable { + + public static final String TYPE = "MIDI"; + + @Override + public MapperViewController getQuickSettingsViewController(Mapper mapper) { + return null; + } + + @Override + public Mapper createNewMapper() { + return new MidiMapper(); + } + + @Override + public void initFeedbackType() { + Midi.getInstance().getMidiDevice().ifPresent(device -> device.initFeedback()); + } + + @Override + public void clearFeedbackType() { + Midi.getInstance().getMidiDevice().ifPresent(device -> device.clearFeedback()); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public String toString() { + return Localization.getString(Strings.Mapper_Midi_Name); + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/listener/KeyboardHandler.java b/PlayWall/src/de/tobias/playpad/action/mapper/listener/KeyboardHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..953b862132bb4ab8fdd2d03dde4ccec0c31a2c33 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/listener/KeyboardHandler.java @@ -0,0 +1,67 @@ +package de.tobias.playpad.action.mapper.listener; + +import java.util.List; + +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.InputType; +import de.tobias.playpad.action.MappingUtils; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import javafx.event.EventHandler; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; + +public class KeyboardHandler implements EventHandler<KeyEvent> { + + private Project project; + private IMainViewController mainViewController; + + public KeyboardHandler(Project project, IMainViewController mainViewController) { + this.project = project; + this.mainViewController = mainViewController; + + mainViewController.getParent().getScene().setOnKeyPressed(this); + mainViewController.getParent().getScene().setOnKeyReleased(this); + mainViewController.getParent().getScene().setOnKeyTyped(this); + } + + private boolean[] keys = new boolean[KeyCode.values().length]; + + @Override + public void handle(KeyEvent event) { + if (!event.isShortcutDown()) { + KeyCode code = null; + InputType type = null; + + if (event.getEventType() == KeyEvent.KEY_PRESSED) { + code = event.getCode(); + type = InputType.PRESSED; + + if (keys[code.ordinal()] == true) { + return; + } + + keys[code.ordinal()] = true; + } else if (event.getEventType() == KeyEvent.KEY_RELEASED) { + code = event.getCode(); + type = InputType.RELEASED; + + keys[code.ordinal()] = false; + } + + // Only execute this, then the right event is triggered and this var is set + if (code != null) { + List<Action> actions = MappingUtils.getActionsForKey(code, Profile.currentProfile().getMappings().getActiveMapping()); + + for (Action action : actions) { + action.performAction(type, project, mainViewController); + } + } + } + } + + public void setProject(Project project) { + this.project = project; + } +} diff --git a/PlayWall/src/de/tobias/playpad/action/mapper/listener/MidiHandler.java b/PlayWall/src/de/tobias/playpad/action/mapper/listener/MidiHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..b63415aed4d0a04705785ab898cf57971ebb42de --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/action/mapper/listener/MidiHandler.java @@ -0,0 +1,66 @@ +package de.tobias.playpad.action.mapper.listener; + +import java.util.List; + +import javax.sound.midi.MidiMessage; + +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.InputType; +import de.tobias.playpad.action.MappingUtils; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.midi.MidiListener; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import javafx.application.Platform; + +/** + * Diese Klasse Verwaltet den MIDI Input und führt die Actions aus. + * + * @author tobias + * + */ +public class MidiHandler implements MidiListener { + + private final Midi midi; + + private IMainViewController mainView; + private Project project; + + public MidiHandler(Midi midi, IMainViewController mainView, Project project) { + this.midi = midi; + this.mainView = mainView; + this.project = project; + } + + /** + * Midi Input Listener + */ + @Override + public void onMidiAction(MidiMessage message) { + int cmd = message.getMessage()[0]; + int key = message.getMessage()[1]; + + // Custom Midi Listener + midi.getMidiDevice().ifPresent(device -> device.onMidiMessage(message)); + + InputType type; + if (message.getMessage()[2] != 0) { + type = InputType.PRESSED; + } else { + type = InputType.RELEASED; + } + + Platform.runLater(() -> + { + List<Action> actions = MappingUtils.getActionsForMidi(cmd, key, Profile.currentProfile().getMappings().getActiveMapping()); + for (Action action : actions) { + action.performAction(type, project, mainView); + } + }); + } + + public void setProject(Project project) { + this.project = project; + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandler.java b/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..86f4617ea6b350352eca1a0b6540cce72cf89102 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandler.java @@ -0,0 +1,252 @@ +package de.tobias.playpad.audio; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.DataLine.Info; +import javax.sound.sampled.FloatControl; +import javax.sound.sampled.Mixer; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.content.AudioContent; +import de.tobias.playpad.settings.Profile; +import de.tobias.utils.util.FileUtils; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.util.Duration; +import javazoom.jl.converter.Converter; +import javazoom.jl.decoder.JavaLayerException; + +public class ClipAudioHandler extends AudioHandler { + + public static final String NAME = "Clip"; + private static final String MP3 = "mp3"; + + private Mixer mixer; + private Clip clip; + private FloatControl volumeControl; + + private ObjectProperty<Duration> durationProperty; + private ObjectProperty<Duration> positionProperty; + + private transient boolean pause; + private transient boolean stop; + + private static final int SLEEP_TIME_POSITION = 50; + private static Thread positionThread; + private static List<ClipAudioHandler> playedHandlers = new ArrayList<>(); + + static { + positionThread = new Thread(() -> + { + while (true) { + try { + if (playedHandlers.isEmpty()) { + synchronized (positionThread) { + positionThread.wait(); + } + } + + for (Iterator<ClipAudioHandler> iterator = playedHandlers.iterator(); iterator.hasNext();) { + ClipAudioHandler handler = iterator.next(); + Pad pad = handler.getContent().getPad(); + + if (handler.clip != null) { + if (handler.clip.getMicrosecondLength() == handler.clip.getMicrosecondPosition() || !handler.pause || handler.stop) { + if (!pad.isLoop()) { + pad.setEof(true); + + // Remove from Loop and Stop + iterator.remove(); + Platform.runLater(() -> pad.setStatus(PadStatus.STOP)); + } + } + } + + // Update der Zeit + Platform.runLater(() -> handler.positionProperty.set(Duration.millis(handler.clip.getMicrosecondPosition() / 1000.0))); + } + + Thread.sleep(SLEEP_TIME_POSITION); + } catch (InterruptedException e) {} catch (ConcurrentModificationException e) {} catch (Exception e) { + e.printStackTrace(); + } + } + }); + + positionThread.start(); + } + + public ClipAudioHandler(PadContent content) { + super(content); + durationProperty = new SimpleObjectProperty<>(); + positionProperty = new SimpleObjectProperty<>(); + } + + @Override + public void play() { + if (!pause) { + clip.setFramePosition(0); + pause = false; + } + stop = false; + + if (getContent().getPad().isLoop()) + clip.loop(Clip.LOOP_CONTINUOUSLY); // Loop + else + clip.start(); // Einfach Play + + boolean start = false; + if (playedHandlers.isEmpty()) { + start = true; + } + + if (!playedHandlers.contains(this)) + playedHandlers.add(this); + if (start) { + synchronized (positionThread) { + positionThread.notify(); + } + } + } + + @Override + public void pause() { + clip.stop(); + pause = true; + if (playedHandlers.contains(this)) + playedHandlers.remove(this); + } + + @Override + public void stop() { + clip.stop(); + stop = true; + pause = false; + if (playedHandlers.contains(this)) + playedHandlers.remove(this); + } + + @Override + public Duration getPosition() { + return positionProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> positionProperty() { + return positionProperty; + } + + @Override + public Duration getDuration() { + return durationProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> durationProperty() { + return durationProperty; + } + + @Override + public void setVolume(double volume, double masterVolume) { + setVolume(masterVolume * volume); + } + + /** + * Lineaer to dB + * + * @param volume + * [0, 1] + */ + private void setVolume(double volume) { + if (volumeControl != null) { + if (volume == 1.0) { + volumeControl.setValue(0); + } else if (volume == 0.0) { + volumeControl.setValue(volumeControl.getMinimum()); + } else { + float newValue = (float) (Math.log10(volume) * 20.0); + if (newValue > volumeControl.getMinimum()) + volumeControl.setValue(newValue); + else + volumeControl.setValue(volumeControl.getMinimum()); + } + } + } + + @Override + public boolean isMediaLoaded() { + return clip != null; + } + + @Override + public void loadMedia() { + mixer = AudioSystem.getMixer(AudioSystem.getMixerInfo()[0]); + + DataLine.Info info = new Info(Clip.class, null); + try { + clip = (Clip) mixer.getLine(info); + + Path path = ((AudioContent) getContent()).getPath(); + URL url = path.toUri().toURL(); + + // Convert wenn mp3 + if (FileUtils.getFileExtention(url.getFile()).toLowerCase().endsWith(MP3)) { + Path wavPath = Profile.currentProfile().getProfileSettings().getCachePath().resolve(path.getFileName().toString() + ".wav"); + url = convertMp3ToWav(path, wavPath, getContent().getPad()); + } + + AudioContent content = (AudioContent) getContent(); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url); + + clip.open(audioInputStream); + volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + + durationProperty.set(Duration.millis(clip.getMicrosecondLength() / 1000.0)); + content.getPad().setStatus(PadStatus.READY); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static URL convertMp3ToWav(Path orgPath, Path wavPath, Pad pad) throws JavaLayerException, URISyntaxException, IOException { + if (Files.notExists(wavPath)) { + Files.createDirectories(wavPath.getParent()); + Files.createFile(wavPath); + + Converter converter = new Converter(); + converter.convert(orgPath.toString(), wavPath.toString()); + } + return wavPath.toUri().toURL(); + } + + @Override + public void unloadMedia() { + clip.close(); + mixer.close(); + + clip = null; + mixer = null; + } + + @Override + public void updateVolume(double masterVolume) { + setVolume(getContent().getPad().getVolume(), masterVolume); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandlerConnect.java b/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandlerConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..b0428e4db1774e8be59177263e9308bd682ca5a6 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/ClipAudioHandlerConnect.java @@ -0,0 +1,19 @@ +package de.tobias.playpad.audio; + +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; +import de.tobias.playpad.viewcontroller.audio.ClipSettingsViewController; + +public class ClipAudioHandlerConnect extends AudioHandlerConnect { + + @Override + public AudioHandler createAudioHandler(PadContent content) { + return new ClipAudioHandler(content); + } + + @Override + public AudioTypeViewController getAudioViewController() { + return new ClipSettingsViewController(); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/audio/JavaFXAudioHandler.java b/PlayWall/src/de/tobias/playpad/audio/JavaFXAudioHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..fe5f86b0ab1ec417e8431d1f733b0ecdd54c1edb --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/JavaFXAudioHandler.java @@ -0,0 +1,160 @@ +package de.tobias.playpad.audio; + +import java.nio.file.Path; + +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.content.AudioContent; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.media.AudioEqualizer; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import javafx.util.Duration; + +public class JavaFXAudioHandler extends AudioHandler implements Equalizable { + + public static final String NAME = "Java FX Media"; + + private Media media; + private MediaPlayer player; + + private ObjectProperty<Duration> durationProperty; + + private BooleanProperty loadedProperty; + + public JavaFXAudioHandler(PadContent content) { + super(content); + + media = null; + player = null; + durationProperty = new SimpleObjectProperty<>(); + + loadedProperty = new SimpleBooleanProperty(); + } + + @Override + public void play() { + player.play(); + } + + @Override + public void pause() { + player.pause(); + } + + @Override + public void stop() { + player.stop(); + } + + @Override + public AudioEqualizer getAudioEqualizer() { + return player.getAudioEqualizer(); + } + + @Override + public Duration getPosition() { + return player.getCurrentTime(); + } + + @Override + public ReadOnlyObjectProperty<Duration> positionProperty() { + return player.currentTimeProperty(); + } + + @Override + public Duration getDuration() { + return durationProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> durationProperty() { + return durationProperty; + } + + @Override + public void setVolume(double volume, double masterVolume) { + if (player != null) + player.setVolume(volume * masterVolume); + } + + @Override + public boolean isMediaLoaded() { + return player != null; + } + + @Override + public void loadMedia() { + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getParent().setBusy(true); + } + }); + + // Old Player + if (player != null) { + getContent().stop(); + } + + Path path = ((AudioContent) getContent()).getPath(); + media = new Media(path.toFile().toURI().toString()); + player = new MediaPlayer(media); + + // Player Listener + player.setOnReady(() -> + { + durationProperty.set(player.getTotalDuration()); + getContent().getPad().setStatus(PadStatus.READY); + loadedProperty.set(true); + + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getParent().setBusy(false); + } + }); + }); + + player.setOnError(() -> + { + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getParent().setBusy(false); + } + }); + loadedProperty.set(false); + getContent().getPad().throwException(path, player.getError()); + }); + player.setOnEndOfMedia(() -> + { + if (!getContent().getPad().isLoop()) { + getContent().getPad().setEof(true); + getContent().getPad().setStatus(PadStatus.STOP); + } else { + // Loop + player.seek(Duration.ZERO); + } + }); + } + + @Override + public void unloadMedia() { + player = null; + media = null; + durationProperty.set(null); + loadedProperty.set(false); + } + + @Override + public void updateVolume(double masterVolume) { + if (player != null) + player.setVolume(getContent().getPad().getVolume() * masterVolume); + } +} diff --git a/PlayWall/src/de/tobias/playpad/audio/JavaFXHandlerConnect.java b/PlayWall/src/de/tobias/playpad/audio/JavaFXHandlerConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..9a5e3fb8cfc71d87b064285e4d8057a43472639b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/JavaFXHandlerConnect.java @@ -0,0 +1,17 @@ +package de.tobias.playpad.audio; + +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; + +public class JavaFXHandlerConnect extends AudioHandlerConnect { + + @Override + public AudioHandler createAudioHandler(PadContent content) { + return new JavaFXAudioHandler(content); + } + + @Override + public AudioTypeViewController getAudioViewController() { + return null; + } +} diff --git a/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandler.java b/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e375c5e2f14febcc47be7684330bea5ac67dfb83 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandler.java @@ -0,0 +1,333 @@ +package de.tobias.playpad.audio; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer.Info; +import javax.sound.sampled.UnsupportedAudioFileException; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.content.AudioContent; +import de.tobias.playpad.settings.Profile; +import de.tobias.utils.util.FileUtils; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.util.Duration; +import javazoom.jl.converter.Converter; +import javazoom.jl.decoder.JavaLayerException; +import kuusisto.tinysound.Music; +import kuusisto.tinysound.TinySound; + +public class TinyAudioHandler extends AudioHandler { + + public static final String SOUND_CARD = "SoundCard"; + + public static final String NAME = "Java Audiostream"; + private static final String MP3 = "mp3"; + private static final int SLEEP_TIME_POSITION = 50; + + private static ExecutorService executorService; + + private static Thread positionThread; + private static List<TinyAudioHandler> playedHandlers = new ArrayList<>(); + + static { + positionThread = new Thread(() -> + { + while (true) { + try { + if (playedHandlers.isEmpty()) { + synchronized (positionThread) { + positionThread.wait(); + } + } + + for (Iterator<TinyAudioHandler> iterator = playedHandlers.iterator(); iterator.hasNext();) { + TinyAudioHandler handler = iterator.next(); + Pad pad = handler.getContent().getPad(); + + if (handler.music != null) { + if (!handler.music.playing()) { + if (!pad.isLoop()) { + pad.setEof(true); + + // Remove from Loop and Stop + iterator.remove(); + Platform.runLater(() -> pad.setStatus(PadStatus.STOP)); + } + } + } + + // Differenz seit Play bis jetzt + long diff = System.currentTimeMillis() - handler.start; + + Duration position = Duration.millis(diff); + + // Für Loop wieder am Anfang anfangen -> Wenn Aktuelle Position + if (handler.duration.isNotNull().get()) { + if (position.greaterThan(handler.duration.get())) { + position.subtract(handler.duration.get()); + handler.start += handler.duration.get().toMillis(); + } + } + + // Update der Zeit + Platform.runLater(() -> handler.position.set(position)); + } + + Thread.sleep(SLEEP_TIME_POSITION); + } catch (InterruptedException e) {} catch (ConcurrentModificationException e) {} catch (Exception e) { + e.printStackTrace(); + } + } + }); + + positionThread.start(); + + executorService = Executors.newFixedThreadPool(1); + Runtime.getRuntime().addShutdownHook(new Thread(() -> executorService.shutdown())); + } + + private Music music; + private boolean pause; // Play fängt immer vorne an. Wenn diese Variable True ist dann wird Resume aufgerufen + + private ObjectProperty<Duration> duration; + private ObjectProperty<Duration> position; + private long start; + + private BooleanProperty loadedProperty; + + public TinyAudioHandler(PadContent content) { + super(content); + + duration = new SimpleObjectProperty<>(); + position = new SimpleObjectProperty<>(); + loadedProperty = new SimpleBooleanProperty(); + } + + @Override + public void play() { + if (music != null) { + if (!pause) { + if (!getContent().getPad().isLoop()) { + music.play(false); // Kein Loop + } else { + music.play(true); // Mit Loop + } + Platform.runLater(() -> position.set(Duration.ZERO)); + start = System.currentTimeMillis(); + } else { + music.resume(); + start = (long) (System.currentTimeMillis() - position.get().toMillis()); + } + pause = false; + + boolean start = false; + if (playedHandlers.isEmpty()) { + start = true; + } + + if (!playedHandlers.contains(this)) + playedHandlers.add(this); + if (start) { + synchronized (positionThread) { + positionThread.notify(); + } + } + } + } + + @Override + public void pause() { + if (music != null) { + music.pause(); + if (playedHandlers.contains(this)) + playedHandlers.remove(this); + pause = true; + } + } + + @Override + public void stop() { + if (music != null) { + music.stop(); + if (playedHandlers.contains(this)) + playedHandlers.remove(this); + pause = false; + } + } + + @Override + public Duration getPosition() { + return position.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> positionProperty() { + return position; + } + + @Override + public Duration getDuration() { + return duration.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> durationProperty() { + return duration; + } + + @Override + public void setVolume(double volume, double masterVolume) { + if (music != null) { + music.setVolume(volume * masterVolume); + } + } + + @Override + public boolean isMediaLoaded() { + return loadedProperty.get(); + } + + @Override + public void loadMedia() { + initTinySound(); + + unloadMedia(); + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getParent().setBusy(true); + } + }); + + executorService.submit(() -> + { + Path path = ((AudioContent) getContent()).getPath(); + try { + URL url = path.toUri().toURL(); + + // Convert wenn mp3 + if (FileUtils.getFileExtention(url.getFile()).toLowerCase().endsWith(MP3)) { + Path wavPath = Profile.currentProfile().getProfileSettings().getCachePath().resolve(path.getFileName().toString() + ".wav"); + url = convertMp3ToWav(path, wavPath, getContent().getPad()); + } + + // Load + music = TinySound.loadMusic(url, true); + calcDuration(url); + + Platform.runLater(() -> + { + loadedProperty.set(true); + getContent().getPad().setStatus(PadStatus.READY); + }); + } catch (Exception e) { + loadedProperty.set(false); + getContent().getPad().throwException(path, e); + e.printStackTrace(); + } finally { + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getParent().setBusy(false); + } + }); + } + }); + } + + private void calcDuration(URL url) throws UnsupportedAudioFileException, IOException { + AudioInputStream iStr = AudioSystem.getAudioInputStream(url); + double max = 1000.0 * (double) iStr.getFrameLength() / (double) iStr.getFormat().getFrameRate(); + Duration duration = Duration.millis(max); + Platform.runLater(() -> this.duration.set(duration)); + iStr.close(); + } + + private static URL convertMp3ToWav(Path orgPath, Path wavPath, Pad pad) throws JavaLayerException, URISyntaxException, IOException { + if (Files.notExists(wavPath)) { + Files.createDirectories(wavPath.getParent()); + Files.createFile(wavPath); + + Converter converter = new Converter(); + converter.convert(orgPath.toString(), wavPath.toString()); + } + return wavPath.toUri().toURL(); + } + + @Override + public void unloadMedia() { + if (music != null) { + music.unload(); + music = null; + } + Platform.runLater(() -> duration.set(null)); + loadedProperty.set(false); + } + + @Override + public void updateVolume(double masterVolume) { + if (music != null) { + music.setVolume(getContent().getPad().getVolume() * masterVolume); + } + } + + public void setMusic(Music music, URL url) throws UnsupportedAudioFileException, IOException { + this.music = music; + calcDuration(url); + loadedProperty.set(true); + } + + private static String audioCardName; + + private void initTinySound() { + String audioCardName = (String) Profile.currentProfile().getProfileSettings().getAudioUserInfo().get(SOUND_CARD); + + if (TinyAudioHandler.audioCardName != null) { + if (!TinyAudioHandler.audioCardName.equals(audioCardName)) { + TinySound.shutdown(); + } + } + + if (!TinySound.isInitialized()) { + // INIT + try { + // Init mit spezieler Sound Card + for (Info info : AudioSystem.getMixerInfo()) { + if (info.getName().equals(audioCardName)) { + TinyAudioHandler.audioCardName = audioCardName; + + TinySound.init(info); + break; + } + } + + } catch (SecurityException | IllegalArgumentException | LineUnavailableException e) { + e.printStackTrace(); + } + // Init mit Default Sound Card, wenn keine Ausgewählt wurde + if (!TinySound.isInitialized()) { + TinySound.init(); + } + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandlerConnect.java b/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandlerConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..3c97f5f9288fd6981970433cdd61503952aac39d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/audio/TinyAudioHandlerConnect.java @@ -0,0 +1,19 @@ +package de.tobias.playpad.audio; + +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; +import de.tobias.playpad.viewcontroller.audio.TinySoundSettingsViewController; + +public class TinyAudioHandlerConnect extends AudioHandlerConnect { + + @Override + public AudioHandler createAudioHandler(PadContent content) { + return new TinyAudioHandler(content); + } + + @Override + public AudioTypeViewController getAudioViewController() { + return new TinySoundSettingsViewController(); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/layout/classic/ClassicCartLayout.java b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicCartLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..3dc08fb0240b1e8654b6de673f749e8d27b2db8e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicCartLayout.java @@ -0,0 +1,238 @@ +package de.tobias.playpad.layout.classic; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.Layout; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.viewcontroller.IPadView; +import de.tobias.utils.util.ColorXMLUtils; +import javafx.application.Platform; +import javafx.scene.paint.Color; + +public class ClassicCartLayout extends Layout implements CartLayout { + + public static final String TYPE = "classic"; + + private Color backgroundColor = Color.TRANSPARENT; + private Color playbackColor = Color.web("#ffb48bbb"); + private Color warnColor = Color.web("#ff8888bb"); + private Color fadeColor = Color.web("#ffea86bb"); + private Color accentColor = Color.BLACK; + + private Color infoLabelColor = Color.BLACK; + private Color titleLabelColor = Color.BLACK; + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Color getPlaybackColor() { + return playbackColor; + } + + public void setPlaybackColor(Color playbackColor) { + this.playbackColor = playbackColor; + } + + public Color getWarnColor() { + return warnColor; + } + + public void setWarnColor(Color warnColor) { + this.warnColor = warnColor; + } + + public Color getFadeColor() { + return fadeColor; + } + + public void setFadeColor(Color fadeColor) { + this.fadeColor = fadeColor; + } + + public Color getInfoLabelColor() { + return infoLabelColor; + } + + public void setInfoLabelColor(Color idLabelColor) { + this.infoLabelColor = idLabelColor; + } + + public Color getTitleLabelColor() { + return titleLabelColor; + } + + public void setTitleLabelColor(Color titleLabelColor) { + this.titleLabelColor = titleLabelColor; + } + + public Color getAccentColor() { + return accentColor; + } + + public void setAccentColor(Color accentColor) { + this.accentColor = accentColor; + } + + public void reset() { + backgroundColor = Color.TRANSPARENT; + playbackColor = Color.web("#ffb48bbb"); + warnColor = Color.web("#ff8888bb"); + fadeColor = Color.web("#ffea86bb"); + + accentColor = Color.BLACK; + infoLabelColor = Color.BLACK; + titleLabelColor = Color.BLACK; + } + + public void load(Element rootElement) { + setBackgroundColor(ColorXMLUtils.load(rootElement.element("BackgroundColor"))); + setPlaybackColor(ColorXMLUtils.load(rootElement.element("PlaybackColor"))); + setWarnColor(ColorXMLUtils.load(rootElement.element("WarnColor"))); + setFadeColor(ColorXMLUtils.load(rootElement.element("FadeColor"))); + setAccentColor(ColorXMLUtils.load(rootElement.element("AccentColor"))); + + Element indexLabelEmement = rootElement.element("InfoLabel"); + if (indexLabelEmement != null) { + setInfoLabelColor(ColorXMLUtils.load(indexLabelEmement.element("Color"))); + } + + Element titleLabelElement = rootElement.element("TitleLabel"); + if (titleLabelElement != null) { + setTitleLabelColor(ColorXMLUtils.load(titleLabelElement.element("Color"))); + } + } + + public void save(Element element) { + ColorXMLUtils.save(element.addElement("BackgroundColor"), backgroundColor); + ColorXMLUtils.save(element.addElement("PlaybackColor"), playbackColor); + ColorXMLUtils.save(element.addElement("WarnColor"), warnColor); + ColorXMLUtils.save(element.addElement("FadeColor"), fadeColor); + ColorXMLUtils.save(element.addElement("AccentColor"), accentColor); + + Element indexLabelElement = element.addElement("InfoLabel"); + ColorXMLUtils.save(indexLabelElement.addElement("Color"), infoLabelColor); + + Element titleLabelElement = element.addElement("TitleLabel"); + ColorXMLUtils.save(titleLabelElement.addElement("Color"), titleLabelColor); + } + + public void save(Path path) throws UnsupportedEncodingException, IOException { + Document document = DocumentHelper.createDocument(); + Element rootElement = document.addElement("layout"); + save(rootElement); + + XMLWriter writer = new XMLWriter(Files.newOutputStream(path), OutputFormat.createPrettyPrint()); + writer.write(document); + writer.close(); + } + + @Override + public CartLayout clone() throws CloneNotSupportedException { + ClassicCartLayout layout = (ClassicCartLayout) super.clone(); + + layout.backgroundColor = Color.color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue(), + backgroundColor.getOpacity()); + layout.playbackColor = Color.color(playbackColor.getRed(), playbackColor.getGreen(), playbackColor.getBlue(), + playbackColor.getOpacity()); + layout.warnColor = Color.color(warnColor.getRed(), warnColor.getGreen(), warnColor.getBlue(), warnColor.getOpacity()); + layout.fadeColor = Color.color(fadeColor.getRed(), fadeColor.getGreen(), fadeColor.getBlue(), fadeColor.getOpacity()); + layout.infoLabelColor = Color.color(infoLabelColor.getRed(), infoLabelColor.getGreen(), infoLabelColor.getBlue(), + infoLabelColor.getOpacity()); + layout.titleLabelColor = Color.color(titleLabelColor.getRed(), titleLabelColor.getGreen(), titleLabelColor.getBlue(), + titleLabelColor.getOpacity()); + + return layout; + } + + public String convertToCss(String classSufix, boolean fullCss) { + StringBuilder builder = new StringBuilder(); + + if (classSufix.isEmpty()) { + builder.append(".fonticon {\n"); + builder.append("\t-fx-text-fill: " + accentColor + ";\n"); + builder.append("}\n"); + + builder.append(".progress-bar {\n"); + builder.append("\t-fx-accent: " + accentColor + ";\n"); + builder.append("}\n"); + + builder.append(".slider .thumb {\n"); + builder.append("-fx-base: " + accentColor + ";\n"); + builder.append("}\n"); + } + + if (fullCss) { + builder.append(".pad" + classSufix + " {\n"); + builder.append("\t-fx-background-color: " + backgroundColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":" + PseudoClasses.PLAY_CALSS.getPseudoClassName() + " {\n"); + builder.append("\t-fx-background-color: " + playbackColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":" + PseudoClasses.WARN_CLASS.getPseudoClassName() + " {\n"); + builder.append("\t-fx-background-color: " + warnColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":" + PseudoClasses.FADE_CLASS.getPseudoClassName() + " {\n"); + builder.append("\t-fx-background-color: " + fadeColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + "-info {\n"); + builder.append("\t-fx-text-fill: " + infoLabelColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + "-title {\n"); + builder.append("\t-fx-text-fill: " + titleLabelColor + ";\n"); + builder.append("}\n"); + + } + + return builder.toString().replace("0x", "#"); + } + + @Override + public void handleWarning(IPadViewController controller, Warning warning) { + final IPadView view = controller.getParent(); + + try { + while (true) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, true); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + Thread.sleep(500); + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.PLAY_CALSS, true); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + }); + Thread.sleep(500); + } + } catch (InterruptedException e) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/layout/classic/ClassicGlobalLayout.java b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicGlobalLayout.java new file mode 100644 index 0000000000000000000000000000000000000000..8618a813cab625a4dca5d5aa260e161fa59be595 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicGlobalLayout.java @@ -0,0 +1,374 @@ +package de.tobias.playpad.layout.classic; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.dom4j.Element; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.Layout; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.viewcontroller.IPadView; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.util.ColorXMLUtils; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.paint.Color; +import javafx.stage.Stage; + +public class ClassicGlobalLayout extends Layout implements GlobalLayout { + + public static final double minWidth = 180; + public static final double minHeight = 100; + + public static final String TYPE = "classic"; + + private ObjectProperty<Theme> themeProperty = new SimpleObjectProperty<>(Theme.LIGHT); + private boolean customLayout = false; + + private Color backgroundColor = Color.TRANSPARENT; + private Color playbackColor = Color.web("#ffb48bbb"); + private Color warnColor = Color.web("#ff8888bb"); + private Color fadeColor = Color.web("#ffea86bb"); + + private Color accentColor = Color.BLACK; + + private int infoLabelFontSize = 13; + private Color infoLabelColor = Color.BLACK; + + private int titleLabelFontSize = 13; + private Color titleLabelColor = Color.BLACK; + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Color getPlaybackColor() { + return playbackColor; + } + + public void setPlaybackColor(Color playbackColor) { + this.playbackColor = playbackColor; + } + + public Color getWarnColor() { + return warnColor; + } + + public void setWarnColor(Color warnColor) { + this.warnColor = warnColor; + } + + public Color getFadeColor() { + return fadeColor; + } + + public void setFadeColor(Color fadeColor) { + this.fadeColor = fadeColor; + } + + public Color getInfoLabelColor() { + return infoLabelColor; + } + + public void setInfoLabelColor(Color idLabelColor) { + this.infoLabelColor = idLabelColor; + } + + public int getInfoLabelFontSize() { + return infoLabelFontSize; + } + + public void setInfoLabelFontSize(int idLabelFontSize) { + this.infoLabelFontSize = idLabelFontSize; + } + + public int getTitleLabelFontSize() { + return titleLabelFontSize; + } + + public void setTitleLabelFontSize(int titleLabelFontSize) { + this.titleLabelFontSize = titleLabelFontSize; + } + + public Color getTitleLabelColor() { + return titleLabelColor; + } + + public void setTitleLabelColor(Color titleLabelColor) { + this.titleLabelColor = titleLabelColor; + } + + public Color getAccentColor() { + return accentColor; + } + + public void setAccentColor(Color accentColor) { + this.accentColor = accentColor; + } + + public Theme getTheme() { + return themeProperty.get(); + } + + public void setTheme(Theme theme) { + themeProperty.set(theme); + } + + public ObjectProperty<Theme> themeProperty() { + return themeProperty; + } + + public boolean isCustomLayout() { + return customLayout; + } + + public void setCustomLayout(boolean customLayout) { + this.customLayout = customLayout; + } + + @Override + public double getMinHeight(int rows) { + return rows * minHeight; + } + + @Override + public double getMinWidth(int columns) { + return columns * minWidth; + } + + @Override + public double getPadHeight() { + return minHeight; + } + + @Override + public double getPadWidth() { + return minWidth; + } + + public void reset() { + themeProperty = new SimpleObjectProperty<>(Theme.LIGHT); + customLayout = false; + + backgroundColor = Color.TRANSPARENT; + playbackColor = Color.web("#ffb48bbb"); + warnColor = Color.web("#ff8888bb"); + fadeColor = Color.web("#ffea86bb"); + + accentColor = Color.BLACK; + + infoLabelFontSize = 13; + infoLabelColor = Color.BLACK; + + titleLabelFontSize = 13; + titleLabelColor = Color.BLACK; + } + + @Override + public void load(Element rootElement) { + if (rootElement.element("Theme") != null) + try { + setTheme(Theme.valueOf(rootElement.element("Theme").getStringValue())); + } catch (IllegalArgumentException e) { + setTheme(Theme.LIGHT); + } + + if (rootElement.element("CustomLayout") != null) + setCustomLayout(Boolean.valueOf(rootElement.element("CustomLayout").getStringValue())); + + setBackgroundColor(ColorXMLUtils.load(rootElement.element("BackgroundColor"))); + setPlaybackColor(ColorXMLUtils.load(rootElement.element("PlaybackColor"))); + setWarnColor(ColorXMLUtils.load(rootElement.element("WarnColor"))); + setFadeColor(ColorXMLUtils.load(rootElement.element("FadeColor"))); + setAccentColor(ColorXMLUtils.load(rootElement.element("AccentColor"))); + + Element indexLabelEmement = rootElement.element("InfoLabel"); + if (indexLabelEmement != null) { + setInfoLabelColor(ColorXMLUtils.load(indexLabelEmement.element("Color"))); + setInfoLabelFontSize(Integer.valueOf(indexLabelEmement.element("FontSize").getStringValue())); + } + + Element titleLabelElement = rootElement.element("TitleLabel"); + if (titleLabelElement != null) { + setTitleLabelColor(ColorXMLUtils.load(titleLabelElement.element("Color"))); + setTitleLabelFontSize(Integer.valueOf(titleLabelElement.element("FontSize").getStringValue())); + } + } + + @Override + public void save(Element element) { + element.addElement("Theme").addText(themeProperty.get().name()); + element.addElement("CustomLayout").addText(String.valueOf(customLayout)); + + ColorXMLUtils.save(element.addElement("BackgroundColor"), backgroundColor); + ColorXMLUtils.save(element.addElement("PlaybackColor"), playbackColor); + ColorXMLUtils.save(element.addElement("WarnColor"), warnColor); + ColorXMLUtils.save(element.addElement("FadeColor"), fadeColor); + ColorXMLUtils.save(element.addElement("AccentColor"), accentColor); + + Element indexLabelElement = element.addElement("InfoLabel"); + ColorXMLUtils.save(indexLabelElement.addElement("Color"), infoLabelColor); + indexLabelElement.addElement("FontSize").addText(String.valueOf(infoLabelFontSize)); + + Element titleLabelElement = element.addElement("TitleLabel"); + ColorXMLUtils.save(titleLabelElement.addElement("Color"), titleLabelColor); + titleLabelElement.addElement("FontSize").addText(String.valueOf(titleLabelFontSize)); + } + + @Override + public GlobalLayout clone() throws CloneNotSupportedException { + ClassicGlobalLayout layout = (ClassicGlobalLayout) super.clone(); + + layout.backgroundColor = Color.color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue(), + backgroundColor.getOpacity()); + layout.playbackColor = Color.color(playbackColor.getRed(), playbackColor.getGreen(), playbackColor.getBlue(), + playbackColor.getOpacity()); + layout.warnColor = Color.color(warnColor.getRed(), warnColor.getGreen(), warnColor.getBlue(), warnColor.getOpacity()); + layout.fadeColor = Color.color(fadeColor.getRed(), fadeColor.getGreen(), fadeColor.getBlue(), fadeColor.getOpacity()); + layout.infoLabelColor = Color.color(infoLabelColor.getRed(), infoLabelColor.getGreen(), infoLabelColor.getBlue(), + infoLabelColor.getOpacity()); + layout.titleLabelColor = Color.color(titleLabelColor.getRed(), titleLabelColor.getGreen(), titleLabelColor.getBlue(), + titleLabelColor.getOpacity()); + layout.infoLabelFontSize = infoLabelFontSize; + layout.titleLabelFontSize = titleLabelFontSize; + + return layout; + } + + public String convertToCSS(String classSufix, boolean fullCss) { + StringBuilder builder = new StringBuilder(); + + if (classSufix.isEmpty()) { + builder.append(".fonticon {\n"); + builder.append("\t-fx-text-fill: " + accentColor + ";\n"); + builder.append("}\n"); + + builder.append(".progress-bar {\n"); + builder.append("\t-fx-accent: " + accentColor + ";\n"); + builder.append("}\n"); + + builder.append(".slider .thumb {\n"); + builder.append("\t-fx-base: " + accentColor + ";\n"); + builder.append("}\n"); + } + + if (fullCss) { + builder.append(".pad" + classSufix + " {\n"); + builder.append("\t-fx-background-color: " + backgroundColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":play {\n"); + builder.append("\t-fx-background-color: " + playbackColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":warn {\n"); + builder.append("\t-fx-background-color: " + warnColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + ":fade {\n"); + builder.append("\t-fx-background-color: " + fadeColor + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + "-info {\n"); + builder.append("\t-fx-text-fill: " + infoLabelColor + ";\n"); + builder.append("\t-fx-font-size: " + infoLabelFontSize + ";\n"); + builder.append("}\n"); + + builder.append(".pad" + classSufix + "-title {\n"); + builder.append("\t-fx-text-fill: " + titleLabelColor + ";\n"); + builder.append("\t-fx-font-size: " + titleLabelFontSize + ";\n"); + builder.append("}\n"); + } + + return builder.toString().replace("0x", "#"); + } + + @Override + public void applyCss(Stage stage) { + // Clear Old + stage.getScene().getStylesheets().clear(); + + // Add Build in Default + stage.getScene().getStylesheets().add("de/tobias/playpad/assets/style.css"); + stage.getScene().getStylesheets().add("de/tobias/playpad/assets/classic_style.css"); + stage.getScene().getStylesheets().add(themeProperty.get().getCss()); + + // User Settings + Path userCss = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, "style.css"); + if (Files.exists(userCss)) + stage.getScene().getStylesheets().add(userCss.toUri().toString()); + } + + @Override + public void applyCssMainView(IMainViewController controller, Stage stage, Project project) { + applyCss(stage); + + // Hard Settings + controller.setGridColor(accentColor); + + Path path = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, "custom_style.css"); + + // Globale CSS -> Immer Akzent, und wenn isCustomLayout dann alles + String css = convertToCSS("", isCustomLayout()); + + // Pad Spezelles Layout immer + for (Pad pad : project.getPads().values()) { + if (pad.isCustomLayout()) { + CartLayout layoutOpt = pad.getLayout(); + css += "\n" + layoutOpt.convertToCss(String.valueOf(pad.getIndex()), true); + } + } + + // Speichern der generierten CSS Datei + try { + Files.write(path, css.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + + stage.getScene().getStylesheets().remove(path.toUri().toString()); + stage.getScene().getStylesheets().add(path.toUri().toString()); + } + + @Override + public void handleWarning(IPadViewController controller, Warning warning) { + final IPadView view = controller.getParent(); + + try { + while (true) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, true); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + Thread.sleep(500); + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.PLAY_CALSS, true); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + }); + Thread.sleep(500); + } + } catch (InterruptedException e) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + } + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/layout/classic/ClassicLayoutConnect.java b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicLayoutConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..bab85710670ae3f9ddc79b6bd7392721f15c0b1b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/classic/ClassicLayoutConnect.java @@ -0,0 +1,49 @@ +package de.tobias.playpad.layout.classic; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.LayoutConnect; +import de.tobias.playpad.viewcontroller.CartLayoutViewController; +import de.tobias.playpad.viewcontroller.GlobalLayoutViewController; +import de.tobias.playpad.viewcontroller.layout.ClassicLayoutCartViewController; +import de.tobias.playpad.viewcontroller.layout.ClassicLayoutGlobalViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class ClassicLayoutConnect extends LayoutConnect { + + private static final String TYPE = "classic"; + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Layout_Classic_Name)); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public CartLayout newCartLayout() { + return new ClassicCartLayout(); + } + + @Override + public GlobalLayout newGlobalLayout() { + return new ClassicGlobalLayout(); + } + + @Override + public CartLayoutViewController getCartLayoutViewController(CartLayout cartLayout) { + return new ClassicLayoutCartViewController(cartLayout); + } + + @Override + public GlobalLayoutViewController getGlobalLayoutViewController(GlobalLayout globalLayout) { + return new ClassicLayoutGlobalViewController(globalLayout); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/layout/classic/Theme.java b/PlayWall/src/de/tobias/playpad/layout/classic/Theme.java new file mode 100644 index 0000000000000000000000000000000000000000..4405ffb716d1456eb44b7eab7970664a05864c49 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/classic/Theme.java @@ -0,0 +1,37 @@ +package de.tobias.playpad.layout.classic; + +import javafx.scene.paint.Color; + +public enum Theme { + + DARK("Dark.css", Color.RED, Color.rgb(40, 40, 40)), + TWILIGHT("Twilight.css", Color.rgb(200, 200, 255), Color.rgb(40, 40, 50)), + LIGHT("Light.css", Color.BLACK, Color.TRANSPARENT); + + private String name; + private Color color; + private Color backgrond; + + private Theme(String name, Color color, Color background) { + this.name = name; + this.color = color; + this.backgrond = background; + } + + public Color getGridColor() { + return color; + } + + public Color getBackground() { + return backgrond; + } + + public String getName() { + return name; + } + + public String getCss() { + return "de/tobias/playpad/assets/style/" + name; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/layout/modern/ModernColor.java b/PlayWall/src/de/tobias/playpad/layout/modern/ModernColor.java new file mode 100644 index 0000000000000000000000000000000000000000..7e94e20e47a289072a6e8c0856f6370d35a798ea --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/modern/ModernColor.java @@ -0,0 +1,113 @@ +package de.tobias.playpad.layout.modern; + +import de.tobias.playpad.DisplayableColor; +import javafx.scene.paint.Color; +import javafx.scene.paint.CycleMethod; +import javafx.scene.paint.LinearGradient; +import javafx.scene.paint.Paint; +import javafx.scene.paint.Stop; + +public enum ModernColor implements DisplayableColor { + + // - Color Hi -- Color Low -- Font ---- Button -- Bar BG -- Bar Track + RED1("#ef9a9a", "#ef5350", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + RED2("#ef5350", "#e53935", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + RED3("#e53935", "#c62828", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + + // --------- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + DARK_RED1("#D92349", "#AD2039", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + DARK_RED2("#C92349", "#8D2039", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + DARK_RED3("#A90329", "#6D0019", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + + // ---- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + PINK1("#f48fb1", "#ec407a", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + PINK2("#ec407a", "#d81b60", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + PINK3("#d81b60", "#ad1457", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + + // -------- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + PURPLE1("#ce93d8", "#ab47bc", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + PURPLE2("#ab47bc", "#8e24aa", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + PURPLE3("#8e24aa", "#6a1b9a", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"), + + // ---- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + LIGHT_BLUE1("#80deea", "#26c6da", "#000000", "#000000", "#FFFFFF", "#000000"), + LIGHT_BLUE2("#26c6da", "#00acc1", "#000000", "#000000", "#FFFFFF", "#000000"), + LIGHT_BLUE3("#00acc1", "#00838f", "#000000", "#000000", "#FFFFFF", "#000000"), + + // ---- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + BLUE1("#90caf9", "#42a5f5", "#000000", "#000000", "#FFFFFF", "#000000"), + BLUE2("#42a5f5", "#1e88e5", "#000000", "#000000", "#FFFFFF", "#000000"), + BLUE3("#1e88e5", "#1565c0", "#000000", "#000000", "#FFFFFF", "#000000"), + + // ------------ BG ------ PLAY ----- Font ---- Button --- Bar BG -- Bar Track + LIGHT_GREEN1("#c5e1a5", "#9ccc65", "#000000", "#000000", "#FFFFFF", "#000000"), + LIGHT_GREEN2("#9ccc65", "#7cb342", "#000000", "#000000", "#FFFFFF", "#000000"), + LIGHT_GREEN3("#7cb342", "#558b2f", "#000000", "#000000", "#FFFFFF", "#000000"), + + // ------- BG ------ PLAY ------ Font ---- Button -- Bar BG -- Bar Track + YELLOW1("#fff59d", "#ffee58", "#000000", "#000000", "#FFFFFF", "#000000"), + YELLOW2("#ffee58", "#fdd835", "#000000", "#000000", "#FFFFFF", "#000000"), + YELLOW3("#fdd835", "#f9a825", "#000000", "#000000", "#FFFFFF", "#000000"), + + // ------- BG ------ PLAY ----- Font ---- Button -- Bar BG -- Bar Track + ORANGE1("#ffcc80", "#ffa726", "#000000", "#000000", "#FFFFFF", "#000000"), + ORANGE2("#ffa726", "#fb8c00", "#000000", "#000000", "#FFFFFF", "#000000"), + ORANGE3("#fb8c00", "#ef6c00", "#000000", "#000000", "#FFFFFF", "#000000"), + + // ---- BG ------ PLAY ----- Font ---- Button --- Bar BG --- Bar Track + GRAY1("#eeeeee", "#cccccc", "#000000", "#000000", "#000000", "#FFFFFF"), + GRAY2("#cccccc", "#aaaaaa", "#000000", "#000000", "#000000", "#FFFFFF"), + GRAY3("#555555", "#333333", "#FFFFFF", "#FFFFFF", "#000000", "#FFFFFF"); + + private final String colorHi; + private final String colorLow; + private final String fontColor; + private final String buttonColor; + private final String playbarColor; + private final String playbarTrackColor; + + private ModernColor(String colorHi, String colorLow, String fontColor, String buttonColor, String playbarColor, String playbarTrackColor) { + this.colorHi = colorHi; + this.colorLow = colorLow; + this.fontColor = fontColor; + this.buttonColor = buttonColor; + this.playbarColor = playbarColor; + this.playbarTrackColor = playbarTrackColor; + } + + public String getColorHi() { + return colorHi; + } + + public String getColorLow() { + return colorLow; + } + + public String getFontColor() { + return fontColor; + } + + public String getButtonColor() { + return buttonColor; + } + + public String getPlaybarColor() { + return playbarColor; + } + + public String getPlaybarTrackColor() { + return playbarTrackColor; + } + + @Override + public Paint getPaint() { + LinearGradient gradient = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, new Stop(0, Color.web(colorHi)), + new Stop(1, Color.web(colorLow))); + return gradient; + } + + public String linearGradient() { + return "linear-gradient(" + getColorHi() + "," + getColorLow() + ")"; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutAnimator.java b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutAnimator.java new file mode 100644 index 0000000000000000000000000000000000000000..e8fd950c69c7eedee044131e901a02c2266cef73 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutAnimator.java @@ -0,0 +1,131 @@ +package de.tobias.playpad.layout.modern; + +import java.util.HashMap; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.FadeableColor; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.viewcontroller.IPadView; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +public class ModernLayoutAnimator { + + // alles nur static, neine objecte von der Klasse + private ModernLayoutAnimator() {} + + private static HashMap<Integer, Timeline> timelines = new HashMap<>(); + + public static void animateFade(IPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) { + int index = padViewController.getPad().getIndex(); + + if (timelines.containsKey(index)) { + timelines.get(index).stop(); + } + + ChangeListener<FadeableColor> fadeListener = new ChangeListener<FadeableColor>() { + + @Override + public void changed(ObservableValue<? extends FadeableColor> observable, FadeableColor oldValue, FadeableColor newValue) { + padViewController.getParent().setStyle("-fx-background-color: " + newValue.toString() + ";"); + } + }; + + ObjectProperty<FadeableColor> backgroundColor = new SimpleObjectProperty<>(); + backgroundColor.addListener(fadeListener); + + Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(backgroundColor, startColor)), + new KeyFrame(duration, new KeyValue(backgroundColor, endColor))); + + timeline.playFromStart(); + timeline.setOnFinished(event -> + { + backgroundColor.removeListener(fadeListener); + padViewController.getParent().setStyle(""); + timelines.remove(index); + }); + + // Memory + timelines.put(index, timeline); + + } + + public static void animateWarn(IPadViewController padViewController, FadeableColor startColor, FadeableColor endColor, Duration duration) { + int index = padViewController.getPad().getIndex(); + + if (timelines.containsKey(index)) { + timelines.get(index).stop(); + } + + ChangeListener<FadeableColor> fadeListener = new ChangeListener<FadeableColor>() { + + @Override + public void changed(ObservableValue<? extends FadeableColor> observable, FadeableColor oldValue, FadeableColor newValue) { + padViewController.getParent().setStyle("-fx-background-color: " + newValue.toString() + ";"); + } + }; + + ObjectProperty<FadeableColor> backgroundColor = new SimpleObjectProperty<>(); + backgroundColor.addListener(fadeListener); + + Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(backgroundColor, startColor)), + new KeyFrame(Duration.seconds(0.125), new KeyValue(backgroundColor, startColor)), + new KeyFrame(Duration.seconds(0.5), new KeyValue(backgroundColor, endColor)), + new KeyFrame(Duration.seconds(0.625), new KeyValue(backgroundColor, endColor))); + + timeline.setAutoReverse(true); + timeline.setCycleCount((int) (duration.toSeconds() / 0.625)); + timeline.playFromStart(); + + timeline.setOnFinished(event -> + { + backgroundColor.removeListener(fadeListener); + padViewController.getParent().setStyle(""); + timelines.remove(index); + }); + + // Memory + timelines.put(index, timeline); + } + + public static void stopAnimation(IPadViewController controller) { + int index = controller.getPad().getIndex(); + + if (timelines.containsKey(index)) { + timelines.get(index).stop(); + } + } + + public static void warnFlash(IPadViewController controller) { + final IPadView view = controller.getParent(); + try { + while (true) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, true); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + Thread.sleep(500); + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.PLAY_CALSS, true); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + }); + Thread.sleep(500); + } + } catch (InterruptedException e) { + Platform.runLater(() -> + { + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + }); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutCart.java b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutCart.java new file mode 100644 index 0000000000000000000000000000000000000000..ba428cd1ed0aa3fee3b07a80e85156cd552c1fda --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutCart.java @@ -0,0 +1,199 @@ +package de.tobias.playpad.layout.modern; + +import org.dom4j.Element; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.FadeableColor; +import de.tobias.playpad.layout.Layout; +import de.tobias.playpad.layout.LayoutColorAssociator; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.view.IPadViewController; +import javafx.scene.paint.Color; +import javafx.util.Duration; + +public class ModernLayoutCart extends Layout implements CartLayout, LayoutColorAssociator { + + public static final String TYPE = "modern"; + + public static final double minWidth = 205; + public static final double minHeight = 110; + + private ModernColor backgroundColor = ModernColor.GRAY1; + private ModernColor playColor = ModernColor.RED1; + + private boolean isWarnAnimation = true; + + public ModernColor getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(ModernColor backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public ModernColor getPlayColor() { + return playColor; + } + + public void setPlayColor(ModernColor playColor) { + this.playColor = playColor; + } + + public boolean isWarnAnimation() { + return isWarnAnimation; + } + + public void setWarnAnimation(boolean isWarnAnimation) { + this.isWarnAnimation = isWarnAnimation; + } + + public void reset() { + backgroundColor = ModernColor.GRAY1; + playColor = ModernColor.RED1; + + isWarnAnimation = true; + } + + @Override + public void load(Element rootElement) { + Element backgroundElement = rootElement.element("BackgroundColor"); + if (backgroundElement != null) { + try { + backgroundColor = ModernColor.valueOf(backgroundElement.getStringValue()); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + Element playElement = rootElement.element("PlayColor"); + if (playElement != null) { + try { + playColor = ModernColor.valueOf(playElement.getStringValue()); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + Element animationElement = rootElement.element("Animation"); + if (animationElement != null) { + Element warnAnimationElement = animationElement.element("Warn"); + if (warnAnimationElement != null) { + isWarnAnimation = Boolean.valueOf(warnAnimationElement.getStringValue()); + } + } + } + + @Override + public void save(Element rootElement) { + rootElement.addElement("BackgroundColor").addText(backgroundColor.name()); + rootElement.addElement("PlayColor").addText(playColor.name()); + Element animationElement = rootElement.addElement("Animation"); + animationElement.addElement("Warn").addText(String.valueOf(isWarnAnimation)); + } + + // Warn Handler -> Animation oder Blinken + @Override + public void handleWarning(IPadViewController controller, Warning warning) { + if (isWarnAnimation) { + warnAnimation(controller, warning); + } else { + ModernLayoutAnimator.warnFlash(controller); + } + } + + @Override + public void stopWarning(IPadViewController controller) { + ModernLayoutAnimator.stopAnimation(controller); + } + + private void warnAnimation(IPadViewController controller, Warning warning) { + FadeableColor stopColor = new FadeableColor(this.backgroundColor.getColorHi(), this.backgroundColor.getColorLow()); + FadeableColor playColor = new FadeableColor(this.playColor.getColorHi(), this.playColor.getColorLow()); + + Duration warnDuration = warning.getTime(); + Pad pad = controller.getPad(); + + if (pad.getContent() instanceof Durationable) { + if (warnDuration.greaterThan(((Durationable) pad.getContent()).getDuration())) { + warnDuration = ((Durationable) pad.getContent()).getDuration(); + } + } + + ModernLayoutAnimator.animateWarn(controller, playColor, stopColor, warnDuration); + } + + // Cart Layout + @Override + public String convertToCss(String prefix, boolean full) { + StringBuilder builder = new StringBuilder(); + + startStyleClass(builder, "pad" + prefix + "-icon"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getButtonColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-playbar .track"); + addStyleParameter(builder, "-fx-base", backgroundColor.getPlaybarColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-playbar .bar"); + addStyleParameter(builder, "-fx-background-color", backgroundColor.getPlaybarTrackColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix); + addStyleParameter(builder, "-fx-background-color", backgroundColor.linearGradient()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-info"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getFontColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-title"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getFontColor()); + endStyleClass(builder); + + buildCss(builder, PseudoClasses.PLAY_CALSS.getPseudoClassName(), prefix, playColor); + buildCss(builder, PseudoClasses.WARN_CLASS.getPseudoClassName(), prefix, backgroundColor); + + return builder.toString().replace("0x", "#"); + } + + private void buildCss(StringBuilder builder, String state, String prefix, ModernColor color) { + startStyleClass(builder, "pad" + prefix + "-info:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getFontColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-title:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getFontColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + ":" + state); + addStyleParameter(builder, "-fx-background-color", color.linearGradient()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-playbar:" + state + " .track"); + addStyleParameter(builder, "-fx-base", color.getPlaybarColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-playbar:" + state + " .bar"); + addStyleParameter(builder, "-fx-background-color", color.getPlaybarTrackColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad" + prefix + "-icon:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getButtonColor()); + endStyleClass(builder); + } + + // Color Associator + @Override + public Color getAssociatedEventColor() { + return Color.web(playColor.getColorHi()); + } + + @Override + public Color getAssociatedStandardColor() { + return Color.web(backgroundColor.getColorHi()); + } +} diff --git a/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutConnect.java b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..d26077ad8100763c42f1b2cd49046670f49cf4bd --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutConnect.java @@ -0,0 +1,49 @@ +package de.tobias.playpad.layout.modern; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.LayoutConnect; +import de.tobias.playpad.viewcontroller.CartLayoutViewController; +import de.tobias.playpad.viewcontroller.GlobalLayoutViewController; +import de.tobias.playpad.viewcontroller.layout.ModernLayoutCartViewController; +import de.tobias.playpad.viewcontroller.layout.ModernLayoutGlobalViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class ModernLayoutConnect extends LayoutConnect { + + private static final String TYPE = "modern"; + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Layout_Modern_Name)); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public CartLayout newCartLayout() { + return new ModernLayoutCart(); + } + + @Override + public GlobalLayout newGlobalLayout() { + return new ModernLayoutGlobal(); + } + + @Override + public CartLayoutViewController getCartLayoutViewController(CartLayout cartLayout) { + return new ModernLayoutCartViewController(cartLayout); + } + + @Override + public GlobalLayoutViewController getGlobalLayoutViewController(GlobalLayout globalLayout) { + return new ModernLayoutGlobalViewController(globalLayout); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutGlobal.java b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutGlobal.java new file mode 100644 index 0000000000000000000000000000000000000000..ae5f91bca5f85098511dbbff5f8fb2827996bb0a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/layout/modern/ModernLayoutGlobal.java @@ -0,0 +1,316 @@ +package de.tobias.playpad.layout.modern; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.dom4j.Element; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.FadeableColor; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.Layout; +import de.tobias.playpad.layout.LayoutColorAssociator; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import javafx.scene.paint.Color; +import javafx.stage.Stage; +import javafx.util.Duration; + +public class ModernLayoutGlobal extends Layout implements GlobalLayout, LayoutColorAssociator { + + public static final String TYPE = "modern"; + + public static final double minWidth = 205; + public static final double minHeight = 110; + + private ModernColor backgroundColor = ModernColor.GRAY1; + private ModernColor playColor = ModernColor.RED1; + + private boolean isWarnAnimation = true; + + private int infoFontSize = 14; + private int titleFontSize = 16; + + public ModernColor getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(ModernColor backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public ModernColor getPlayColor() { + return playColor; + } + + public void setPlayColor(ModernColor playColor) { + this.playColor = playColor; + } + + public boolean isWarnAnimation() { + return isWarnAnimation; + } + + public void setWarnAnimation(boolean isWarnAnimation) { + this.isWarnAnimation = isWarnAnimation; + } + + public int getInfoFontSize() { + return infoFontSize; + } + + public void setInfoFontSize(int infoFontSize) { + this.infoFontSize = infoFontSize; + } + + public int getTitleFontSize() { + return titleFontSize; + } + + public void setTitleFontSize(int titleFontSize) { + this.titleFontSize = titleFontSize; + } + + @Override + public double getMinHeight(int rows) { + return rows * minHeight; + } + + @Override + public double getMinWidth(int columns) { + return columns * minWidth; + } + + @Override + public double getPadHeight() { + return minHeight; + } + + @Override + public double getPadWidth() { + return minWidth; + } + + public void reset() { + backgroundColor = ModernColor.GRAY1; + playColor = ModernColor.RED1; + + isWarnAnimation = true; + + infoFontSize = 14; + titleFontSize = 16; + } + + private String convertToCSS() { + StringBuilder builder = new StringBuilder(); + + startStyleClass(builder, "pad-icon"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getButtonColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad-playbar .track"); + addStyleParameter(builder, "-fx-base", backgroundColor.getPlaybarColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad-playbar .bar"); + addStyleParameter(builder, "-fx-background-color", backgroundColor.getPlaybarTrackColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad"); + addStyleParameter(builder, "-fx-background-color", backgroundColor.linearGradient()); + endStyleClass(builder); + + startStyleClass(builder, "pad-info"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getFontColor()); + addStyleParameter(builder, "-fx-font-size", infoFontSize); + endStyleClass(builder); + + startStyleClass(builder, "pad-title"); + addStyleParameter(builder, "-fx-text-fill", backgroundColor.getFontColor()); + addStyleParameter(builder, "-fx-font-size", titleFontSize); + endStyleClass(builder); + + buildStateCss(builder, PseudoClasses.PLAY_CALSS.getPseudoClassName(), playColor); + buildStateCss(builder, PseudoClasses.WARN_CLASS.getPseudoClassName(), backgroundColor); + + return builder.toString().replace("0x", "#"); + } + + private void buildStateCss(StringBuilder builder, String state, ModernColor color) { + startStyleClass(builder, "pad-info:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getFontColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad-title:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getFontColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad:" + state); + addStyleParameter(builder, "-fx-background-color", color.linearGradient()); + endStyleClass(builder); + + startStyleClass(builder, "pad-playbar:" + state + " .track"); + addStyleParameter(builder, "-fx-base", color.getPlaybarColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad-playbar:" + state + " .bar"); + addStyleParameter(builder, "-fx-background-color", color.getPlaybarTrackColor()); + endStyleClass(builder); + + startStyleClass(builder, "pad-icon:" + state); + addStyleParameter(builder, "-fx-text-fill", color.getButtonColor()); + endStyleClass(builder); + } + + @Override + public void applyCss(Stage stage) { + // Clear Old + stage.getScene().getStylesheets().clear(); + + // Add Build in Default + stage.getScene().getStylesheets().add("de/tobias/playpad/assets/style.css"); + stage.getScene().getStylesheets().add("de/tobias/playpad/assets/modern_style.css"); + + // User Settings + Path userCss = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, "style.css"); + if (Files.exists(userCss)) + stage.getScene().getStylesheets().add(userCss.toUri().toString()); + } + + @Override + public void applyCssMainView(IMainViewController controller, Stage stage, Project project) { + applyCss(stage); + + controller.setGridColor(Color.TRANSPARENT); + + Path path = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, "custom_style.css"); + + String css = convertToCSS(); + + // Pad Spezelles Layout immer + for (Pad pad : project.getPads().values()) { + if (pad.isCustomLayout()) { + CartLayout layoutOpt = pad.getLayout(Profile.currentProfile().getProfileSettings().getLayoutType()); + css += "\n" + layoutOpt.convertToCss(String.valueOf(pad.getIndex()), true); + } + } + + // Speichern der generierten CSS Datei + try { + Files.write(path, css.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + + stage.getScene().getStylesheets().remove(path.toUri().toString()); + stage.getScene().getStylesheets().add(path.toUri().toString()); + } + + @Override + public void load(Element rootElement) { + Element backgroundElement = rootElement.element("BackgroundColor"); + if (backgroundElement != null) { + try { + backgroundColor = ModernColor.valueOf(backgroundElement.getStringValue()); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + Element playElement = rootElement.element("PlayColor"); + if (playElement != null) { + try { + playColor = ModernColor.valueOf(playElement.getStringValue()); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + Element animationElement = rootElement.element("Animation"); + if (animationElement != null) { + Element warnAnimationElement = animationElement.element("Warn"); + if (warnAnimationElement != null) { + isWarnAnimation = Boolean.valueOf(warnAnimationElement.getStringValue()); + } + } + + Element infoFontSizeElement = rootElement.element("InfoFontSize"); + if (infoFontSizeElement != null) { + try { + infoFontSize = Integer.valueOf(infoFontSizeElement.getStringValue()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + Element titleFontSizeElement = rootElement.element("TitleFontSize"); + if (titleFontSizeElement != null) { + try { + infoFontSize = Integer.valueOf(titleFontSizeElement.getStringValue()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + + @Override + public void save(Element rootElement) { + rootElement.addElement("BackgroundColor").addText(backgroundColor.name()); + rootElement.addElement("PlayColor").addText(playColor.name()); + Element animationElement = rootElement.addElement("Animation"); + animationElement.addElement("Warn").addText(String.valueOf(isWarnAnimation)); + rootElement.addElement("InfoFontSize").addText(String.valueOf(infoFontSize)); + rootElement.addElement("TitleFontSize").addText(String.valueOf(titleFontSize)); + } + + // Warn Handler -> Animation oder Blinken + @Override + public void handleWarning(IPadViewController controller, Warning warning) { + if (isWarnAnimation) { + warnAnimation(controller, warning); + } else { + ModernLayoutAnimator.warnFlash(controller); + } + } + + @Override + public void stopWarning(IPadViewController controller) { + ModernLayoutAnimator.stopAnimation(controller); + } + + private void warnAnimation(IPadViewController controller, Warning warning) { + FadeableColor stopColor = new FadeableColor(this.backgroundColor.getColorHi(), this.backgroundColor.getColorLow()); + FadeableColor playColor = new FadeableColor(this.playColor.getColorHi(), this.playColor.getColorLow()); + + Duration warnDuration = warning.getTime(); + Pad pad = controller.getPad(); + + if (pad.getContent() instanceof Durationable) { + if (warnDuration.greaterThan(((Durationable) pad.getContent()).getDuration())) { + warnDuration = ((Durationable) pad.getContent()).getDuration(); + } + } + + ModernLayoutAnimator.animateWarn(controller, playColor, stopColor, warnDuration); + } + + // Color Associator + @Override + public Color getAssociatedEventColor() { + return Color.web(playColor.getColorHi()); + } + + @Override + public Color getAssociatedStandardColor() { + return Color.web(backgroundColor.getColorHi()); + } +} diff --git a/PlayWall/src/de/tobias/playpad/midi/device/PD12.java b/PlayWall/src/de/tobias/playpad/midi/device/PD12.java new file mode 100644 index 0000000000000000000000000000000000000000..df4ceb01d9a4883b17752afdbab848abdae5c03d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/midi/device/PD12.java @@ -0,0 +1,60 @@ +package de.tobias.playpad.midi.device; + +import javax.sound.midi.MidiMessage; +import javax.sound.midi.SysexMessage; + +import de.tobias.playpad.action.feedback.DisplayableFeedbackColor; +import de.tobias.playpad.action.feedback.Feedback; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.settings.Profile; +import javafx.application.Platform; + +public class PD12 extends Device { + + public static final String NAME = "PD 12"; + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean supportFeedback() { + return false; + } + + @Override + public void onMidiMessage(MidiMessage message) { + if (message instanceof SysexMessage) { + if (message.getMessage().length == 8) { + if (message.getMessage()[0] == -16 && message.getMessage()[1] == 127 && message.getMessage()[2] == 127 + && message.getMessage()[3] == 4 && message.getMessage()[4] == 1 && message.getMessage()[5] == 0 + && message.getMessage()[7] == -9) { + int volume = message.getMessage()[6]; + double volume_ = volume / 127.0; + Platform.runLater(() -> Profile.currentProfile().getProfileSettings().setVolume(volume_)); + } + } + } + } + + @Override + public void handleFeedback(FeedbackMessage type, int key, Feedback feedback) {} + + @Override + public void initFeedback() {} + + @Override + public void clearFeedback() {} + + @Override + public DisplayableFeedbackColor getColor(int id) { + return null; + } + + @Override + public DisplayableFeedbackColor[] getColors() { + return null; + } +} diff --git a/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java b/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java new file mode 100644 index 0000000000000000000000000000000000000000..9e2d50338664957373c7f1e6ca4d6a66718e5017 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java @@ -0,0 +1,279 @@ +package de.tobias.playpad.pad.content; + +import java.io.FileNotFoundException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import org.dom4j.Element; + +import de.tobias.playpad.audio.AudioHandler; +import de.tobias.playpad.audio.AudioRegistry; +import de.tobias.playpad.audio.Equalizable; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.conntent.Fadeable; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.Pauseable; +import de.tobias.playpad.project.ProjectExporter; +import de.tobias.playpad.settings.Profile; +import javafx.animation.Transition; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ChangeListener; +import javafx.scene.media.AudioEqualizer; +import javafx.util.Duration; + +public class AudioContent extends PadContent implements Pauseable, Durationable, Fadeable, Equalizable { + + private static final String TYPE = "audio"; + + private Path path; + private AudioHandler audioHandler; + + private ObjectProperty<Duration> durationProperty = new SimpleObjectProperty<>(); + private ObjectProperty<Duration> positionProperty = new SimpleObjectProperty<>(); + + private ChangeListener<Number> volumeListener; + + private transient Transition transition; + + public AudioContent(Pad pad) { + super(pad); + volumeListener = (a, b, c) -> + { + audioHandler.setVolume(c.doubleValue(), Profile.currentProfile().getProfileSettings().getVolume()); + }; + } + + public AudioContent(Pad pad, Path path) { + this(pad); + this.path = path; + } + + public Path getPath() { + return path; + } + + public void setPath(Path path) { + this.path = path; + } + + @Override + public void handlePath(Path path) { + unloadMedia(); + setPath(path); + loadMedia(); + } + + @Override + public void setMasterVolume(double masterVolume) { + if (audioHandler != null) { + audioHandler.setVolume(getPad().getVolume(), masterVolume); + } + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public void play() { + getPad().setEof(false); + audioHandler.play(); + } + + @Override + public void pause() { + audioHandler.pause(); + } + + @Override + public boolean stop() { + audioHandler.stop(); + return true; + } + + @Override + public void fadeIn() { + if (transition != null) { + transition.stop(); + } + + if (getPad().getFade().getFadeIn().toMillis() > 0) { + double masterVolume = Profile.currentProfile().getProfileSettings().getVolume(); + audioHandler.setVolume(0, masterVolume); + transition = new Transition() { + + { + setCycleDuration(getPad().getFade().getFadeIn()); + } + + @Override + protected void interpolate(double frac) { + audioHandler.setVolume(frac * getPad().getVolume(), masterVolume); + } + }; + transition.setOnFinished(e -> + { + transition = null; + }); + transition.play(); + } + } + + @Override + public void fadeOut(Runnable onFinish) { + if (transition != null) { + transition.stop(); + } + + if (getPad().getFade().getFadeOut().toMillis() > 0) { + transition = new Transition() { + + { + setCycleDuration(getPad().getFade().getFadeOut()); + } + + @Override + protected void interpolate(double frac) { + double masterVolume = Profile.currentProfile().getProfileSettings().getVolume(); + audioHandler.setVolume(getPad().getVolume() - frac * getPad().getVolume(), masterVolume); + } + }; + transition.setOnFinished(event -> + { + onFinish.run(); + + double masterVolume = Profile.currentProfile().getProfileSettings().getVolume(); + audioHandler.setVolume(getPad().getVolume(), masterVolume); + transition = null; + }); + transition.play(); + } else { + onFinish.run(); + } + } + + @Override + public boolean isFading() { + if (transition != null) { + return true; + } + return false; + } + + @Override + public AudioEqualizer getAudioEqualizer() { + if (audioHandler instanceof Equalizable) { + return ((Equalizable) audioHandler).getAudioEqualizer(); + } + return null; + } + + @Override + public boolean isPadLoaded() { + return audioHandler.isMediaLoaded(); + } + + @Override + public Duration getDuration() { + return durationProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> durationProperty() { + return durationProperty; + } + + @Override + public Duration getPosition() { + return positionProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> positionProperty() { + return positionProperty; + } + + @Override + public void loadMedia() { + audioHandler = AudioRegistry.geAudioType().createAudioHandler(this); + if (Files.exists(path)) { + audioHandler.loadMedia(); + + durationProperty.bind(audioHandler.durationProperty()); + positionProperty.bind(audioHandler.positionProperty()); + + getPad().volumeProperty().addListener(volumeListener); + } else { + getPad().throwException(path, new FileNotFoundException()); + } + } + + @Override + public void unloadMedia() { + durationProperty.unbind(); + positionProperty.unbind(); + + getPad().volumeProperty().removeListener(volumeListener); + + if (audioHandler != null) + audioHandler.unloadMedia(); + try { + getPad().setStatus(PadStatus.EMPTY); + } catch (Exception e) { + Platform.runLater(() -> getPad().setStatus(PadStatus.EMPTY)); + } + } + + @Override + public void load(Element element) { + path = Paths.get(element.getStringValue()); + } + + @Override + public void save(Element element) { + element.addText(path.toString()); + } + + @Override + public void importMedia(Path mediaFolder, FileSystem zipfs, Element element) { + String fileName = Paths.get(element.getStringValue()).getFileName().toString(); + Path mediaFile = zipfs.getPath(ProjectExporter.mediaFolder, fileName); + if (Files.exists(mediaFile)) { + Path desFile = mediaFolder.resolve(fileName); + + try { + if (Files.notExists(desFile.getParent())) { + Files.createDirectories(desFile.getParent()); + } + Files.copy(mediaFile, desFile, StandardCopyOption.REPLACE_EXISTING); + + element.setText(desFile.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void exportMedia(FileSystem mediaFolder, Element element) { + Path desPath = mediaFolder.getPath(ProjectExporter.mediaFolder, path.getFileName().toString()); + try { + if (Files.notExists(desPath.getParent())) { + Files.createDirectories(desPath.getParent()); + } + Files.copy(path, desPath, StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java b/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..9566b9095e2e83096c5b08b2f62cc679883465d8 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java @@ -0,0 +1,105 @@ +package de.tobias.playpad.pad.content; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import de.tobias.playpad.pad.view.IPadContentView; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.option.AudioTabViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.scene.text.TextAlignment; + +public class AudioContentConnect extends PadContentConnect { + + public static final String TYPE = "audio"; + public static final String[] FILE_EXTENSION = { "*.mp3", "*.wav" }; + + private FontIcon icon; + + public AudioContentConnect() { + icon = new FontIcon(FontAwesomeType.MUSIC); + icon.setSize(30); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public PadContent newInstance(Pad pad) { + return new AudioContent(pad); + } + + @Override + public String[] getSupportedTypes() { + return FILE_EXTENSION; + } + + @Override + public IPadContentView getPadContentPreview(Pad pad, Pane parentNode) { + if (pad.getContent() != null) { + AudioContentView view = new AudioContentView(pad, parentNode); + + return view; + } else { + return null; + } + } + + @Override + public SettingsTabViewController getSettingsTabViewController(boolean activePlayer) { + return new AudioTabViewController(activePlayer); + } + + private class AudioContentView implements IPadContentView { + + private Label nameLabel; + + public AudioContentView(Pad pad, Pane parentNode) { + nameLabel = new Label(); + nameLabel.textProperty().bind(pad.nameProperty()); + + nameLabel.setWrapText(true); + nameLabel.setAlignment(Pos.CENTER); + nameLabel.setTextAlignment(TextAlignment.CENTER); + + nameLabel.prefWidthProperty().bind(parentNode.widthProperty()); + nameLabel.setMaxHeight(Double.MAX_VALUE); + VBox.setVgrow(nameLabel, Priority.ALWAYS); + } + + @Override + public Node getNode() { + return nameLabel; + } + + @Override + public void unconnect() { + nameLabel.textProperty().unbind(); + } + } + + // UI - DnD + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty(Localization.getString(Strings.Content_Audio_Name)); + } + + @Override + public Node getGraphics() { + return icon; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/pad/drag/MoveDragMode.java b/PlayWall/src/de/tobias/playpad/pad/drag/MoveDragMode.java new file mode 100644 index 0000000000000000000000000000000000000000..bf6bbc47811da7668d9c046ce1c68610dd02528d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/drag/MoveDragMode.java @@ -0,0 +1,41 @@ +package de.tobias.playpad.pad.drag; + +import de.tobias.playpad.project.Project; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; + +public class MoveDragMode extends PadDragMode { + + private static final String TYPE = "move"; + + private FontIcon icon; + + public MoveDragMode() { + icon = new FontIcon(FontAwesomeType.ARROWS); + icon.setSize(30); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty("Tauschen"); // TODO Localize + } + + @Override + public Node getGraphics() { + return icon; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public void handle(int oldPad, int newPad, Project project) { + project.movePads(oldPad, newPad); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/pad/drag/ReplaceDragMode.java b/PlayWall/src/de/tobias/playpad/pad/drag/ReplaceDragMode.java new file mode 100644 index 0000000000000000000000000000000000000000..a01255fe87f135bd006b9e9cc8c3c6672ac07d8d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/drag/ReplaceDragMode.java @@ -0,0 +1,41 @@ +package de.tobias.playpad.pad.drag; + +import de.tobias.playpad.project.Project; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; + +public class ReplaceDragMode extends PadDragMode { + + private static final String TYPE = "replace"; + + private FontIcon icon; + + public ReplaceDragMode() { + icon = new FontIcon(FontAwesomeType.ARROW_CIRCLE_RIGHT); + icon.setSize(30); + } + + @Override + public StringProperty displayProperty() { + return new SimpleStringProperty("Ersetzen"); // TODO Localize + } + + @Override + public Node getGraphics() { + return icon; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public void handle(int oldPad, int newPad, Project project) { + project.replacePads(oldPad, newPad); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/pad/listener/PadContentListener.java b/PlayWall/src/de/tobias/playpad/pad/listener/PadContentListener.java new file mode 100644 index 0000000000000000000000000000000000000000..54a756291bf94eadf7604b74b0df646beb44b913 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/listener/PadContentListener.java @@ -0,0 +1,53 @@ +package de.tobias.playpad.pad.listener; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +public class PadContentListener implements ChangeListener<PadContent> { + + private Pad pad; + private PadViewController controller; + + public PadContentListener(PadViewController controller) { + this.controller = controller; + } + + public void setPad(Pad pad) { + this.pad = pad; + } + + @Override + public void changed(ObservableValue<? extends PadContent> observable, PadContent oldValue, PadContent newValue) { + // wenn Content change, update preview & buttons + controller.getParent().setPreviewContent(pad); + controller.getParent().addDefaultButton(pad); + + controller.updateButtonDisable(); + controller.updateTimeLabel(); + + // Remove old listener + if (oldValue != null && oldValue instanceof Durationable) { + Durationable oldDurationable = (Durationable) oldValue; + oldDurationable.durationProperty().removeListener(controller.getPadDurationListener()); + oldDurationable.positionProperty().removeListener(controller.getPadPositionListener()); + } + + // set new content listener / bindings + if (newValue instanceof Durationable) { + controller.getParent().showPlaybar(true); + + Durationable durationable = (Durationable) newValue; + durationable.durationProperty().addListener(controller.getPadDurationListener()); + durationable.positionProperty().addListener(controller.getPadPositionListener()); + + // Init Duration + controller.getPadDurationListener().changed(null, null, durationable.getDuration()); + } else { + controller.getParent().showPlaybar(false); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/pad/listener/PadDurationListener.java b/PlayWall/src/de/tobias/playpad/pad/listener/PadDurationListener.java new file mode 100644 index 0000000000000000000000000000000000000000..2058d3a1e30e520e032487d185561cdb0f8f6b33 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/listener/PadDurationListener.java @@ -0,0 +1,22 @@ +package de.tobias.playpad.pad.listener; + +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +public class PadDurationListener implements ChangeListener<Duration> { + + private PadViewController controller; + + public PadDurationListener(PadViewController controller) { + this.controller = controller; + } + + @Override + public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { + if (controller != null) { + controller.updateTimeLabel(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/pad/listener/PadPositionListener.java b/PlayWall/src/de/tobias/playpad/pad/listener/PadPositionListener.java new file mode 100644 index 0000000000000000000000000000000000000000..40e9b5b6a491b1fbe583d035f07b546ea85c283a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/listener/PadPositionListener.java @@ -0,0 +1,106 @@ +package de.tobias.playpad.pad.listener; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.conntent.Fadeable; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +public class PadPositionListener implements ChangeListener<Duration>, Runnable { + + private Pad pad; + private PadViewController controller; + + public PadPositionListener(PadViewController controller) { + this.controller = controller; + } + + public void setPad(Pad pad) { + this.pad = pad; + } + + boolean send = false; + private Thread warningThread; + + @Override + public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { + if (oldValue == Duration.ZERO) { + setSend(false); + } + + // Progressbar (Prozente) + if (pad != null) { + // Zeit aktualiesieren bei Play und wenn Fade Out ist + if (pad.getContent() instanceof Durationable && (pad.getStatus() == PadStatus.PLAY + || (pad.getContent() instanceof Fadeable && ((Fadeable) pad.getContent()).isFading()))) { + + Durationable durationable = (Durationable) pad.getContent(); + Duration totalDuration = durationable.getDuration(); + + double value = newValue.toMillis() / totalDuration.toMillis(); + controller.getParent().getPlayBar().setProgress(value); + + // Label (Restlaufzeit) + controller.updateTimeLabel(); + + // Warning nur wenn kein Loop und nur wenn Play, da sonst schon anderer Zustand und Warning nicht mehr richtig Reseted wird + if (!pad.isLoop() && pad.getStatus() == PadStatus.PLAY) { + // Warning + Warning warning = pad.getWarning(); + Duration rest = durationable.getDuration().subtract(newValue); + double seconds = rest.toSeconds(); + + if (warning.getTime().toSeconds() > seconds && !send) { + startWarningThread(); + send = true; + } + } + } + } + } + + public void setSend(boolean send) { + this.send = send; + } + + /* + * EoF GUI Flash + */ + @Override + public void run() { + Warning warning = pad.getWarning(); + + if (pad.isCustomLayout()) { + pad.getLayout().handleWarning(controller, warning); + } else { + Profile.currentProfile().currentLayout().handleWarning(controller, warning); + } + } + + protected void startWarningThread() { + if (warningThread != null) { + warningThread.interrupt(); + } + warningThread = new Thread(this); + warningThread.start(); + } + + public void stopWaning() { + if (warningThread != null) { + warningThread.interrupt(); + warningThread = null; + } + + if (pad.isCustomLayout()) { + pad.getLayout().stopWarning(controller); + } else { + Profile.currentProfile().currentLayout().stopWarning(controller); + } + controller.getParent().setStyle(""); + } +} diff --git a/PlayWall/src/de/tobias/playpad/pad/listener/PadStatusListener.java b/PlayWall/src/de/tobias/playpad/pad/listener/PadStatusListener.java new file mode 100644 index 0000000000000000000000000000000000000000..117e2aa04ccf8572531368b51767dc99feb5b06c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/pad/listener/PadStatusListener.java @@ -0,0 +1,75 @@ +package de.tobias.playpad.pad.listener; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +public class PadStatusListener implements ChangeListener<PadStatus> { + + private PadViewController controller; + + public PadStatusListener(PadViewController controller) { + this.controller = controller; + } + + @Override + public void changed(ObservableValue<? extends PadStatus> observable, PadStatus oldValue, PadStatus newValue) { + controller.updateButtonDisable(); + controller.updateTimeLabel(); + controller.getParent().setErrorLabelActive(false); + + switch (newValue) { + case PLAY: + // Reset Warning Feedback for UI + controller.getPadPositionListener().setSend(false); + + // UI Styling + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, true); + break; + + case PAUSE: + controller.getPadPositionListener().stopWaning(); + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, false); + controller.getParent().pseudoClassState(PseudoClasses.FADE_CLASS, false); + controller.getParent().pseudoClassState(PseudoClasses.WARN_CLASS, false); + break; + + case STOP: + controller.getPadPositionListener().stopWaning(); + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, false); + controller.getParent().pseudoClassState(PseudoClasses.FADE_CLASS, false); + controller.getParent().pseudoClassState(PseudoClasses.WARN_CLASS, false); + controller.getParent().setStyle(""); + break; + + case READY: + controller.getPadPositionListener().stopWaning(); + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, false); + controller.getParent().pseudoClassState(PseudoClasses.FADE_CLASS, false); + controller.getParent().pseudoClassState(PseudoClasses.WARN_CLASS, false); + controller.getParent().setStyle(""); // Cleanup from warning UI + break; + case ERROR: + controller.getParent().setErrorLabelActive(true); + + controller.getPadPositionListener().stopWaning(); + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, false); + controller.getParent().pseudoClassState(PseudoClasses.FADE_CLASS, false); + controller.getParent().pseudoClassState(PseudoClasses.WARN_CLASS, false); + controller.getParent().setStyle(""); // Cleanup from warning UI + break; + + case EMPTY: + controller.getPadPositionListener().stopWaning(); + controller.getParent().pseudoClassState(PseudoClasses.PLAY_CALSS, false); + controller.getParent().pseudoClassState(PseudoClasses.FADE_CLASS, false); + controller.getParent().pseudoClassState(PseudoClasses.WARN_CLASS, false); + controller.getParent().setStyle(""); // Cleanup from warning UI + break; + default: + break; + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItem.java b/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItem.java new file mode 100644 index 0000000000000000000000000000000000000000..b7e056734a4a0985f231369a7ec3e77018f886b4 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItem.java @@ -0,0 +1,167 @@ +package de.tobias.playpad.trigger; + +import java.util.ArrayList; +import java.util.List; + +import org.dom4j.Element; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.playpad.viewcontroller.main.IMainViewController; + +public class CartTriggerItem extends TriggerItem { + + private List<Integer> carts; + private boolean allCarts; + private PadStatus newStatus; // Only Play, Pause, Stop + + public CartTriggerItem() { + newStatus = PadStatus.PLAY; + allCarts = false; + carts = new ArrayList<Integer>() { + + private static final long serialVersionUID = 1L; + + @Override + public boolean add(Integer e) { + if (!contains(e)) + return super.add(e); + else + return false; + } + }; + } + + public List<Integer> getCarts() { + return carts; + } + + public boolean isAllCarts() { + return allCarts; + } + + public void setAllCarts(boolean allCarts) { + this.allCarts = allCarts; + } + + public PadStatus getNewStatus() { + return newStatus; + } + + public void setNewStatus(PadStatus newStatus) { + if (newStatus == PadStatus.PLAY || newStatus == PadStatus.PAUSE || newStatus == PadStatus.STOP) + this.newStatus = newStatus; + } + + @Override + public String getType() { + return CartTriggerItemConnect.TYPE; + } + + @Override + public void performAction(Pad pad, Project project, IMainViewController controller, Profile profile) { + if (allCarts) { + for (Pad cart : project.getPads().values()) { + if (cart.getIndex() != pad.getIndex()) + cart.setStatus(newStatus); + } + } else { + for (int cart : carts) { + if (cart != pad.getIndex()) + project.getPad(cart).setStatus(newStatus); + } + } + } + + private static final String CART_ELEMENT = "Cart"; + private static final String STATUS_ATTR = "Status"; + private static final String ALLCARTS_ATTR = "all"; + + @Override + public void load(Element element) { + super.load(element); + + if (element.attributeValue(STATUS_ATTR) != null) + setNewStatus(PadStatus.valueOf(element.attributeValue(STATUS_ATTR))); + if (element.attributeValue(ALLCARTS_ATTR) != null) + setAllCarts(Boolean.valueOf(element.attributeValue(ALLCARTS_ATTR))); + + for (Object cartObj : element.elements(CART_ELEMENT)) { + if (cartObj instanceof Element) { + Element cartElement = (Element) cartObj; + carts.add(Integer.valueOf(cartElement.getStringValue())); + } + } + } + + @Override + public void save(Element element) { + super.save(element); + + element.addAttribute(STATUS_ATTR, newStatus.name()); + element.addAttribute(ALLCARTS_ATTR, String.valueOf(allCarts)); + + for (int cart : carts) { + Element cartElement = element.addElement(CART_ELEMENT); + cartElement.addText(String.valueOf(cart)); + } + } + + public void setCartsString(String string) { + if (string != null) { + carts.clear(); + string = string.replace(" ", ""); + for (String part : string.split(",")) { + if (part.contains("-")) { + if (part.split("-").length == 2) { + int start = Integer.valueOf(part.split("-")[0]); + int end = Integer.valueOf(part.split("-")[1]); + + for (int i = start; i <= end; i++) { + carts.add(i - 1); + } + } + } else { + int cart = Integer.valueOf(part); + carts.add(cart - 1); + } + } + carts.sort(Integer::compareTo); + } + } + + public String getCartsString() { + String string = ""; + int startValue = -1; + + for (int i = 0; i < carts.size(); i++) { + if (i + 1 < carts.size()) { + if (carts.get(i) + 1 == carts.get(i + 1)) { + if (startValue == -1) { + startValue = carts.get(i); + } + } else { + if (startValue != -1) + string += (startValue + 1) + "-" + (carts.get(i) + 1) + ","; + else + string += (carts.get(i) + 1) + ","; + startValue = -1; + + } + } else { + if (startValue == -1) { + string += (carts.get(i) + 1) + ","; + } else { + string += (startValue + 1) + "-" + (carts.get(i) + 1) + ","; + } + } + } + if (string.isEmpty()) { + return null; + } + return string.substring(0, string.length() - 1); + } +} diff --git a/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItemConnect.java b/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItemConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..873488ad8610e1abe8d583607b298e4bcbf0d249 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/trigger/CartTriggerItemConnect.java @@ -0,0 +1,34 @@ +package de.tobias.playpad.trigger; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.tigger.Trigger; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.playpad.tigger.TriggerItemConnect; +import de.tobias.playpad.viewcontroller.option.pad.trigger.CartTriggerViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; + +public class CartTriggerItemConnect extends TriggerItemConnect { + + public final static String TYPE = "Cart"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public TriggerItem newInstance(Trigger trigger) { + return new CartTriggerItem(); + } + + @Override + public ContentViewController getSettingsController(TriggerItem item) { + return new CartTriggerViewController((CartTriggerItem) item); + } + + @Override + public String toString() { + return Localization.getString(Strings.Trigger_Cart_Name); + } +} diff --git a/PlayWall/src/de/tobias/playpad/trigger/TriggerWrapper.java b/PlayWall/src/de/tobias/playpad/trigger/TriggerWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..039e62de4361faa4ec38ca83756d1b65171e74d4 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/trigger/TriggerWrapper.java @@ -0,0 +1,50 @@ +package de.tobias.playpad.trigger; + +import de.tobias.playpad.Displayable; +import de.tobias.playpad.Strings; +import de.tobias.playpad.tigger.Trigger; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.utils.util.Localization; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class TriggerWrapper implements Displayable { + + private Trigger trigger; + + public TriggerWrapper(Trigger trigger) { + this.trigger = trigger; + updateString(); + } + + public Trigger getTrigger() { + return trigger; + } + + private StringProperty displayable = new SimpleStringProperty(); + + @Override + public StringProperty displayProperty() { + return displayable; + } + + public void addItem(TriggerItem triggerItem) { + trigger.addItem(triggerItem); + updateString(); + } + + public void removeItem(TriggerItem item) { + trigger.removeItem(item); + updateString(); + } + + private void updateString() { + displayable.set(toString()); + } + + @Override + public String toString() { + String triggerPointName = Localization.getString(Strings.TriggerPoint_BaseName + trigger.getTriggerPoint().name()); + return Localization.getString(Strings.TriggerPoint_toString, triggerPointName, trigger.getItems().size()); + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItem.java b/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItem.java new file mode 100644 index 0000000000000000000000000000000000000000..e6124d754ebfdca60885c9e0f5633e050d45d6ed --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItem.java @@ -0,0 +1,20 @@ +package de.tobias.playpad.trigger; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.playpad.viewcontroller.main.IMainViewController; + +public class VolumeTriggerItem extends TriggerItem { + + @Override + public String getType() { + return VolumeTriggerItemConnect.TYPE; + } + + @Override + public void performAction(Pad pad, Project project, IMainViewController controller, Profile profile) { + + } +} diff --git a/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItemConnect.java b/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItemConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..7c242e425d7461f1e5a0f4f0ff9e99b09f67b517 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/trigger/VolumeTriggerItemConnect.java @@ -0,0 +1,33 @@ +package de.tobias.playpad.trigger; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.tigger.Trigger; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.playpad.tigger.TriggerItemConnect; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; + +public class VolumeTriggerItemConnect extends TriggerItemConnect { + + public final static String TYPE = "Volume"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public TriggerItem newInstance(Trigger trigger) { + return new VolumeTriggerItem(); + } + + @Override + public ContentViewController getSettingsController(TriggerItem item) { + return null; + } + + @Override + public String toString() { + return Localization.getString(Strings.Trigger_Volume_Name); + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/ColorView.java b/PlayWall/src/de/tobias/playpad/view/ColorView.java new file mode 100644 index 0000000000000000000000000000000000000000..ff09b68021852c4ebf68451ece4cb165c952fccf --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/ColorView.java @@ -0,0 +1,48 @@ +package de.tobias.playpad.view; + +import java.util.function.Consumer; + +import de.tobias.playpad.DisplayableColor; +import javafx.geometry.Insets; +import javafx.scene.layout.GridPane; +import javafx.scene.shape.Rectangle; + +public class ColorView extends GridPane { + + public ColorView(DisplayableColor startColor, DisplayableColor[] colors, Consumer<DisplayableColor> finish) { + double size = Math.sqrt(colors.length); + int iSize = (int) size; + if (size != iSize) { + iSize++; + } + + setVgap(5); + setHgap(5); + + setPadding(new Insets(5)); + + int index = 0; + for (int y = 0; y < iSize; y++) { + for (int x = 0; x < iSize; x++) { + if (index < colors.length) { + DisplayableColor color = colors[index++]; + + // Style in CSS + Rectangle rectangle = new Rectangle(40, 40); + rectangle.setFill(color.getPaint()); + + rectangle.getStyleClass().add("color-view-item"); + + // Gestrichelte Linie + if (color == startColor) { + rectangle.getStrokeDashArray().addAll(3.0); + } + + // EventHandler + rectangle.setOnMouseReleased(event -> finish.accept(color)); + add(rectangle, x, y); + } + } + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/EmptyPadView.java b/PlayWall/src/de/tobias/playpad/view/EmptyPadView.java new file mode 100644 index 0000000000000000000000000000000000000000..cc05c503e6d240fbad846193c16dfb10064b2c40 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/EmptyPadView.java @@ -0,0 +1,23 @@ +package de.tobias.playpad.view; + +import de.tobias.playpad.Strings; +import de.tobias.utils.util.Localization; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.scene.text.TextAlignment; + +public class EmptyPadView extends Label { + + public EmptyPadView(Pane parent) { + super(Localization.getString(Strings.Content_Empty)); + setWrapText(true); + setAlignment(Pos.CENTER); + setTextAlignment(TextAlignment.CENTER); + prefWidthProperty().bind(parent.widthProperty()); + setMaxHeight(Double.MAX_VALUE); + VBox.setVgrow(this, Priority.ALWAYS); + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/ExceptionButton.java b/PlayWall/src/de/tobias/playpad/view/ExceptionButton.java new file mode 100644 index 0000000000000000000000000000000000000000..c663458ceaeb0ae65caa3ce8d93ab7d6c7394b9f --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/ExceptionButton.java @@ -0,0 +1,54 @@ +package de.tobias.playpad.view; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.util.Localization; +import javafx.scene.control.Button; +import javafx.stage.FileChooser; +import javafx.stage.Window; + +public class ExceptionButton<T> { + + public static ExceptionButton<Path> FILE_NOT_FOUND_EXCEPTION = new ExceptionButton<>(Localization.getString(Strings.Error_Fix_NewFile), + new Handler<Path>() { + + @Override + public Path handle(Pad pad, Window owner) { + FileChooser chooser = new FileChooser(); + + Object lastFolder = ApplicationUtils.getApplication().getUserDefaults().getData("openFolder"); + if (lastFolder != null) { + Path path = Paths.get(lastFolder.toString()); + chooser.setInitialDirectory(path.toFile()); + } + File file = chooser.showOpenDialog(owner); + return file != null ? file.toPath() : null; + } + }); + + public static interface Handler<T> { + + public T handle(Pad pad, Window owner); + } + + private String title; + private Handler<T> handler; + + public ExceptionButton(String title, Handler<T> handler) { + this.title = title; + this.handler = handler; + } + + public Button getButton() { + return new Button(title); + } + + public Handler<T> getHandler() { + return handler; + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/FileDragOptionView.java b/PlayWall/src/de/tobias/playpad/view/FileDragOptionView.java new file mode 100644 index 0000000000000000000000000000000000000000..191a1aca1d2aeceedfa394d1989fc5f90ce717c3 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/FileDragOptionView.java @@ -0,0 +1,179 @@ +package de.tobias.playpad.view; + +import java.util.Set; +import java.util.function.Consumer; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import javafx.animation.FadeTransition; +import javafx.animation.ParallelTransition; +import javafx.animation.ScaleTransition; +import javafx.animation.Transition; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.paint.Color; +import javafx.scene.text.TextAlignment; + +public class FileDragOptionView { + + private HBox optionPane; + private Pane parent; + + private Transition inTransition; + private Transition outTransition; + + public FileDragOptionView(Pane pane) { + parent = pane; + + optionPane = new HBox(); + optionPane.prefWidthProperty().bind(parent.widthProperty()); + optionPane.prefHeightProperty().bind(parent.heightProperty()); + optionPane.setBackground(new Background(new BackgroundFill(new Color(0.2, 0.2, 0.2, 0.8), new CornerRadii(10), new Insets(0)))); + optionPane.setAlignment(Pos.CENTER); + optionPane.setPadding(new Insets(5)); + optionPane.setSpacing(5); + + inTransition = createTransition(true); + outTransition = createTransition(false); + + } + + public Transition getInTransition() { + return inTransition; + } + + public void setInTransition(Transition inTransition) { + this.inTransition = inTransition; + } + + public Transition getOutTransition() { + return outTransition; + } + + public void setOutTransition(Transition outTransition) { + this.outTransition = outTransition; + } + + private Transition createTransition(boolean in) { + FadeTransition fadeTransition = new FadeTransition(); + fadeTransition.setNode(optionPane); + + ScaleTransition scaleTransition = new ScaleTransition(); + scaleTransition.setNode(optionPane); + + if (in) { + fadeTransition.setFromValue(0); + fadeTransition.setToValue(1); + + scaleTransition.setFromX(1.3); + scaleTransition.setFromY(1.3); + scaleTransition.setToX(1); + scaleTransition.setToY(1); + } else { + fadeTransition.setFromValue(1); + fadeTransition.setToValue(0); + + scaleTransition.setFromX(1); + scaleTransition.setFromY(1); + scaleTransition.setToX(1.3); + scaleTransition.setToY(1.3); + } + + ParallelTransition parallelTransition = new ParallelTransition(fadeTransition, scaleTransition); + + parallelTransition.setOnFinished((e) -> + { + if (!in) + parent.getChildren().remove(optionPane); + }); + return parallelTransition; + } + + private PadContentConnect selectedConnect; + + public void showDropOptions(Set<PadContentConnect> options) { + if (!parent.getChildren().contains(optionPane)) { + selectedConnect = null; + + parent.getChildren().add(optionPane); + optionPane.getChildren().clear(); + + for (PadContentConnect connect : options.stream().sorted().toArray(value -> new PadContentConnect[value])) { + Label label = new Label(); + label.getStyleClass().add("dnd-file-option"); + label.textProperty().bind(connect.displayProperty()); + Node graphics = connect.getGraphics(); + if (graphics != null) { + graphics.setStyle("-fx-text-fill: white;"); + label.setGraphic(graphics); + } + label.setWrapText(true); + + label.setOnDragOver(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, true); + selectedConnect = connect; + }); + label.setOnDragExited(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, false); + selectedConnect = null; + }); + + label.setUserData(connect); + + label.setAlignment(Pos.CENTER); + label.setTextAlignment(TextAlignment.CENTER); + label.setContentDisplay(ContentDisplay.TOP); + + label.maxWidthProperty().bind(optionPane.widthProperty().divide(options.size()).subtract(12.5)); + label.setMaxHeight(Double.MAX_VALUE); + HBox.setHgrow(label, Priority.ALWAYS); + + optionPane.getChildren().add(label); + } + + inTransition.play(); + } + + } + + public void showDropOptions(Set<PadContentConnect> options, Consumer<PadContentConnect> onFinish) { + showDropOptions(options); + + for (Node node : optionPane.getChildren()) { + if (node instanceof Label) { + Label label = (Label) node; + label.setOnMouseClicked(ev -> + { + onFinish.accept((PadContentConnect) label.getUserData()); + }); + label.setOnMouseEntered(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, true); + }); + label.setOnMouseExited(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, false); + }); + } + } + } + + public PadContentConnect getSelectedConnect() { + return selectedConnect; + } + + public void hide() { + outTransition.play(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/MapperOverviewViewController.java b/PlayWall/src/de/tobias/playpad/view/MapperOverviewViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..5174571a9eb60fc7c40d33f6428c9317d6c79a7e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/MapperOverviewViewController.java @@ -0,0 +1,161 @@ +package de.tobias.playpad.view; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MapperRegistry; +import de.tobias.playpad.action.mapper.MapperViewController; +import de.tobias.playpad.viewcontroller.IMapperOverviewViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.scene.Parent; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; + +public class MapperOverviewViewController implements IMapperOverviewViewController { + + private VBox root; + private VBox mappingView; + private HBox addMappingBox; + + private Action action; + private List<MapperViewController> controllers; + + private List<MapperAddListener> addListeners; + + private Pane parent; + private ScrollPane scrollPane; + + public MapperOverviewViewController() { + controllers = new ArrayList<>(); + addListeners = new ArrayList<>(); + + init(); + } + + public void init() { + root = new VBox(14); + + mappingView = new VBox(); + mappingView.setSpacing(14); + + addMappingBox = new HBox(14); + + Label headline = new Label(PlayPadMain.getUiResourceBundle().getString("action.mapper.headline")); + headline.setUnderline(true); + root.getChildren().addAll(headline, mappingView, addMappingBox); + + Set<String> types = MapperRegistry.getTypes(); + types.stream().sorted().forEach(item -> + { + Button button = new Button(MapperRegistry.getMapperConnect(item).toString(), new FontIcon(FontAwesomeType.PLUS_CIRCLE)); + button.setContentDisplay(ContentDisplay.TOP); + button.setPrefWidth(150); + + button.setOnAction(e -> + { + // Adds a mapper to the action + MapperViewController controller = onAddMapper(item); + controller.showInputMapperUI(); + + }); + addMappingBox.getChildren().add(button); + }); + } + + private MapperViewController onAddMapper(String type) { + Mapper mapper = MapperRegistry.getMapperConnect(type).createNewMapper(); + action.addMapper(mapper); + return addMapperView(type, mapper); + } + + private MapperViewController addMapperView(String type, Mapper mapper) { + MapperViewController controller = (MapperViewController) mapper.getSettingsViewController(); + if (controller != null) { + Button deleteButton = new Button("", new FontIcon(FontAwesomeType.TRASH)); + + HBox hbox = new HBox(controller.getParent(), deleteButton); + hbox.setSpacing(14); + + mappingView.getChildren().addAll(hbox); + + deleteButton.setOnAction((e) -> + { + action.removeMapper(mapper); + mappingView.getChildren().removeAll(hbox); + }); + } + controllers.add(controller); + addListeners.forEach(i -> i.onAdd(mapper, controller)); + return controller; + } + + @Override + public List<MapperViewController> getControllers() { + return controllers; + } + + @Override + public Parent getParent() { + return root; + } + + @Override + public void addMapperAddListener(MapperAddListener addListener) { + addListeners.add(addListener); + } + + private void createSubViews(Action action) { + controllers.clear(); + mappingView.getChildren().clear(); + + List<Mapper> mapperSorted = action.getMapperSorted(); + for (int i = 0; i < mapperSorted.size(); i++) { + Mapper mapper = mapperSorted.get(i); + addMapperView(mapper.getType(), mapper); + } + } + + @Override + public void showAction(Action action, Pane parent) { + this.action = action; + + createSubViews(action); + + if (this.parent != null) { + this.parent.getChildren().remove(getParent()); // Rmeove from old Parent + } + if (this.scrollPane != null) { + this.scrollPane.setContent(null); + } + + this.parent = parent; + this.parent.getChildren().add(getParent()); // Add to new Parent + } + + @Override + public void showAction(Action action, ScrollPane parent) { + this.action = action; + + createSubViews(action); + + if (this.parent != null) { + this.parent.getChildren().remove(getParent()); // Rmeove from old Parent + } + if (this.scrollPane != null) { + this.scrollPane.setContent(null); + } + + this.scrollPane = parent; + this.scrollPane.setContent(getParent()); // Add to new Parent + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/MapperQuickSettingsView.java b/PlayWall/src/de/tobias/playpad/view/MapperQuickSettingsView.java new file mode 100644 index 0000000000000000000000000000000000000000..095e711a9c10d6f16951a7946f87b22b3fd5c390 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/MapperQuickSettingsView.java @@ -0,0 +1,58 @@ +package de.tobias.playpad.view; + +import java.util.List; + +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MapperRegistry; +import de.tobias.playpad.action.mapper.MapperViewController; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; + +public class MapperQuickSettingsView { + + private VBox optionPane; + private Pane root; + + public MapperQuickSettingsView(Pane pane) { + root = pane; + + optionPane = new VBox(); + optionPane.prefWidthProperty().bind(root.widthProperty()); + optionPane.prefHeightProperty().bind(root.heightProperty()); + optionPane.setBackground(new Background(new BackgroundFill(new Color(0.2, 0.2, 0.2, 0.8), new CornerRadii(10), new Insets(0)))); + optionPane.setAlignment(Pos.CENTER); + optionPane.setPadding(new Insets(5)); + optionPane.setSpacing(5); + } + + private PadContentConnect selectedConnect; + + public void showDropOptions(List<Mapper> mappers) { + if (!root.getChildren().contains(optionPane)) { + selectedConnect = null; + + root.getChildren().add(optionPane); + optionPane.getChildren().clear(); + + for (Mapper mapper : mappers) { + MapperViewController controller = MapperRegistry.getMapperConnect(mapper.getType()).getQuickSettingsViewController(mapper); + optionPane.getChildren().add(controller.getParent()); + } + } + } + + public PadContentConnect getSelectedConnect() { + return selectedConnect; + } + + public void hide() { + root.getChildren().remove(optionPane); + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/PadDragOptionView.java b/PlayWall/src/de/tobias/playpad/view/PadDragOptionView.java new file mode 100644 index 0000000000000000000000000000000000000000..16a64687ce031eac36fb3ccd1d14adc61cf7488e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/PadDragOptionView.java @@ -0,0 +1,155 @@ +package de.tobias.playpad.view; + +import java.util.Collection; + +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.pad.drag.PadDragMode; +import javafx.animation.FadeTransition; +import javafx.animation.ParallelTransition; +import javafx.animation.ScaleTransition; +import javafx.animation.Transition; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.paint.Color; +import javafx.scene.text.TextAlignment; + +public class PadDragOptionView { + + private HBox optionPane; + private Pane parent; + + private Transition inTransition; + private Transition outTransition; + + public PadDragOptionView(Pane pane) { + parent = pane; + + optionPane = new HBox(); + optionPane.prefWidthProperty().bind(parent.widthProperty()); + optionPane.prefHeightProperty().bind(parent.heightProperty()); + optionPane.setBackground(new Background(new BackgroundFill(new Color(0.2, 0.2, 0.2, 0.8), new CornerRadii(10), new Insets(0)))); + optionPane.setAlignment(Pos.CENTER); + optionPane.setPadding(new Insets(5)); + optionPane.setSpacing(5); + + inTransition = createTransition(true); + outTransition = createTransition(false); + + } + + public Transition getInTransition() { + return inTransition; + } + + public void setInTransition(Transition inTransition) { + this.inTransition = inTransition; + } + + public Transition getOutTransition() { + return outTransition; + } + + public void setOutTransition(Transition outTransition) { + this.outTransition = outTransition; + } + + private Transition createTransition(boolean in) { + FadeTransition fadeTransition = new FadeTransition(); + fadeTransition.setNode(optionPane); + + ScaleTransition scaleTransition = new ScaleTransition(); + scaleTransition.setNode(optionPane); + + if (in) { + fadeTransition.setFromValue(0); + fadeTransition.setToValue(1); + + scaleTransition.setFromX(1.3); + scaleTransition.setFromY(1.3); + scaleTransition.setToX(1); + scaleTransition.setToY(1); + } else { + fadeTransition.setFromValue(1); + fadeTransition.setToValue(0); + + scaleTransition.setFromX(1); + scaleTransition.setFromY(1); + scaleTransition.setToX(1.3); + scaleTransition.setToY(1.3); + } + + ParallelTransition parallelTransition = new ParallelTransition(fadeTransition, scaleTransition); + + parallelTransition.setOnFinished((e) -> + { + if (!in) + parent.getChildren().remove(optionPane); + }); + return parallelTransition; + } + + private PadDragMode selectedConnect; + + public void showDropOptions(Collection<PadDragMode> options) { + if (!parent.getChildren().contains(optionPane)) { + selectedConnect = null; + + parent.getChildren().add(optionPane); + optionPane.getChildren().clear(); + + for (PadDragMode connect : options.stream().sorted().toArray(value -> new PadDragMode[value])) { + Label label = new Label(); + label.getStyleClass().add("dnd-file-option"); + label.textProperty().bind(connect.displayProperty()); + Node graphics = connect.getGraphics(); + if (graphics != null) { + graphics.setStyle("-fx-text-fill: white;"); + label.setGraphic(graphics); + } + label.setWrapText(true); + + label.setOnDragOver(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, true); + selectedConnect = connect; + }); + label.setOnDragExited(e -> + { + label.pseudoClassStateChanged(PseudoClasses.HOVER_CLASS, false); + selectedConnect = null; + }); + + label.setUserData(connect); + + label.setAlignment(Pos.CENTER); + label.setTextAlignment(TextAlignment.CENTER); + label.setContentDisplay(ContentDisplay.TOP); + + label.maxWidthProperty().bind(optionPane.widthProperty().divide(options.size()).subtract(12.5)); + label.setMaxHeight(Double.MAX_VALUE); + HBox.setHgrow(label, Priority.ALWAYS); + + optionPane.getChildren().add(label); + } + + inTransition.play(); + } + } + + public PadDragMode getSelectedPadDragMode() { + return selectedConnect; + } + + public void hide() { + outTransition.play(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/view/PadView.java b/PlayWall/src/de/tobias/playpad/view/PadView.java new file mode 100644 index 0000000000000000000000000000000000000000..ab24ea66cd1532538280e52f8823829f86954686 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/view/PadView.java @@ -0,0 +1,364 @@ +package de.tobias.playpad.view; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.Pauseable; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.pad.view.IPadContentView; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.viewcontroller.IPadView; +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.ui.scene.BusyView; +import javafx.css.PseudoClass; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +public class PadView extends StackPane implements IPadView { + + private Label indexLabel; + private Label loopLabel; + private Label triggerLabel; + private Label messageLabel; + + private HBox infoBox; + private Label timeLabel; + + private HBox preview; + private IPadContentView previewContent; + + private ProgressBar playBar; + private Button playButton; + private Button pauseButton; + private Button stopButton; + private Button newButton; + private Button settingsButton; + private HBox buttonBox; + + private VBox root; + private BusyView busyView; + + private transient PadViewController controller; // Reference to its controller + + public PadView(PadViewController controller) { + this.controller = controller; + + root = new VBox(); + busyView = new BusyView(this); + + indexLabel = new Label(); + + loopLabel = new Label(); // Active über Visible + loopLabel.setGraphic(new FontIcon(FontAwesomeType.REPEAT)); + + triggerLabel = new Label(); + triggerLabel.setGraphic(new FontIcon(FontAwesomeType.EXTERNAL_LINK)); + + messageLabel = new Label(); + messageLabel.setGraphic(new FontIcon(FontAwesomeType.WARNING)); + + timeLabel = new Label(); + + infoBox = new HBox(); // childern in addDefaultButton() + infoBox.setSpacing(5); + + preview = new HBox(); + HBox.setHgrow(preview, Priority.ALWAYS); + VBox.setVgrow(preview, Priority.ALWAYS); + + HBox.setHgrow(timeLabel, Priority.ALWAYS); + timeLabel.setMaxWidth(Double.MAX_VALUE); + timeLabel.setAlignment(Pos.CENTER_RIGHT); + + playBar = new ProgressBar(0); + playBar.prefWidthProperty().bind(root.widthProperty()); + + // Buttons + playButton = new Button("", new FontIcon(FontAwesomeType.PLAY)); + playButton.setFocusTraversable(false); + playButton.setOnAction(controller); + pauseButton = new Button("", new FontIcon(FontAwesomeType.PAUSE)); + pauseButton.setFocusTraversable(false); + pauseButton.setOnAction(controller); + stopButton = new Button("", new FontIcon(FontAwesomeType.STOP)); + stopButton.setFocusTraversable(false); + stopButton.setOnAction(controller); + newButton = new Button("", new FontIcon(FontAwesomeType.FOLDER_OPEN)); + newButton.setFocusTraversable(false); + newButton.setOnAction(controller); + settingsButton = new Button("", new FontIcon(FontAwesomeType.GEAR)); + settingsButton.setFocusTraversable(false); + settingsButton.setOnAction(controller); + + // Button HBOX + buttonBox = new HBox(); // childern in addDefaultButton() + + root.getChildren().addAll(infoBox, preview, playBar, buttonBox); + getChildren().addAll(root); + } + + // wird über den Status listener gesteuert + public void setErrorLabelActive(boolean active) { + messageLabel.setVisible(active); + } + + public void setTriggerLabelActive(boolean active) { + triggerLabel.setVisible(active); + } + + public Label getIndexLabel() { + return indexLabel; + } + + public Label getTimeLabel() { + return timeLabel; + } + + public ProgressBar getPlayBar() { + return playBar; + } + + public Button getPlayButton() { + return playButton; + } + + public Button getPauseButton() { + return pauseButton; + } + + public Button getStopButton() { + return stopButton; + } + + public Button getNewButton() { + return newButton; + } + + public Button getSettingsButton() { + return settingsButton; + } + + public HBox getButtonBox() { + return buttonBox; + } + + public HBox getInfoBox() { + return infoBox; + } + + public IPadViewController getController() { + return controller; + } + + public Label getLoopLabel() { + return loopLabel; + } + + public Label getErrorLabel() { + return messageLabel; + } + + public VBox getRoot() { + return root; + } + + public void setPreviewContent(Pad pad) { + if (previewContent != null) { + previewContent.unconnect(); + } + + if (pad != null) { + PadContent content = pad.getContent(); + if (content != null) { + try { + previewContent = PadContentRegistry.getPadContentConnect(content.getType()).getPadContentPreview(pad, preview); + Node node = previewContent.getNode(); + + node.getStyleClass().addAll("pad-title", "pad" + pad.getIndex() + "-title"); + preview.getChildren().setAll(node); + return; + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + } + EmptyPadView view = new EmptyPadView(preview); + if (pad != null) { + view.getStyleClass().addAll("pad-title", "pad" + pad.getIndex() + "-title"); + } else { + view.getStyleClass().addAll("pad-title"); + } + preview.getChildren().setAll(view); + } + + public void clearPreviewContent() { + if (previewContent != null) { + previewContent.unconnect(); + } + setPreviewContent(null); + } + + public void addDefaultButton(Pad pad) { + if (pad != null) { + if (pad.getContent() != null) { + if (pad.getContent() instanceof Pauseable) { + buttonBox.getChildren().setAll(playButton, pauseButton, stopButton, newButton, settingsButton); + } else { + buttonBox.getChildren().setAll(playButton, stopButton, newButton, settingsButton); + } + } else { + buttonBox.getChildren().setAll(newButton, settingsButton); + } + } + infoBox.getChildren().setAll(indexLabel, loopLabel, triggerLabel, messageLabel, timeLabel); + + // Buttons unten Full Width + buttonBox.prefWidthProperty().bind(widthProperty()); + for (Node child : buttonBox.getChildren()) { + if (child instanceof Region) { + HBox.setHgrow(child, Priority.ALWAYS); + ((Region) child).setMaxWidth(Double.MAX_VALUE); + } + } + + // alle Labels in der InfoBox sollen die gleiche Höhe haben, damit die Icons auf gleicher höhe sind + for (Node child : infoBox.getChildren()) { + if (child instanceof Label) { + ((Label) child).setMaxHeight(Double.MAX_VALUE); + } + } + } + + public void setBusy(boolean busy) { + busyView.showProgress(busy); + } + + public void pseudoClassState(PseudoClass pseudoClass, boolean active) { + pseudoClassStateChanged(pseudoClass, active); + indexLabel.pseudoClassStateChanged(pseudoClass, active); + timeLabel.pseudoClassStateChanged(pseudoClass, active); + loopLabel.getGraphic().pseudoClassStateChanged(pseudoClass, active); + triggerLabel.getGraphic().pseudoClassStateChanged(pseudoClass, active); + messageLabel.getGraphic().pseudoClassStateChanged(pseudoClass, active); + + if (preview != null) { + preview.getChildren().forEach(i -> i.pseudoClassStateChanged(pseudoClass, active)); + } + + playBar.pseudoClassStateChanged(pseudoClass, active); + + playButton.getGraphic().pseudoClassStateChanged(pseudoClass, active); + pauseButton.getGraphic().pseudoClassStateChanged(pseudoClass, active); + stopButton.getGraphic().pseudoClassStateChanged(pseudoClass, active); + newButton.getGraphic().pseudoClassStateChanged(pseudoClass, active); + settingsButton.getGraphic().pseudoClassStateChanged(pseudoClass, active); + } + + public void addStyleClasses(Pad pad) { + getStyleClass().addAll("pad", "pad" + pad.getIndex()); + + indexLabel.getStyleClass().addAll("pad-index", "pad" + pad.getIndex() + "-index", "pad-info", "pad" + pad.getIndex() + "-info"); + timeLabel.getStyleClass().addAll("pad-time", "pad" + pad.getIndex() + "-time", "pad-info", "pad" + pad.getIndex() + "-info"); + loopLabel.getGraphic().getStyleClass().addAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + triggerLabel.getGraphic().getStyleClass().addAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + messageLabel.getGraphic().getStyleClass().addAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + + preview.getChildren().forEach(i -> i.getStyleClass().addAll("pad-title", "pad" + pad.getIndex() + "-title")); + + playBar.getStyleClass().addAll("pad-playbar", "pad" + pad.getIndex() + "-playbar"); + + playButton.getStyleClass().addAll("pad-button", "pad-playbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-playbutton"); + pauseButton.getStyleClass().addAll("pad-button", "pad-pausebutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-pausebutton"); + stopButton.getStyleClass().addAll("pad-button", "pad-stopbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-stopbutton"); + newButton.getStyleClass().addAll("pad-button", "pad-newbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-newbutton"); + settingsButton.getStyleClass().addAll("pad-button", "pad-settingsbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-settingsbutton"); + + playButton.getGraphic().getStyleClass().addAll("pad-icon", "pad-playbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-playbutton-icon"); + pauseButton.getGraphic().getStyleClass().addAll("pad-icon", "pad-pausebutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-pausebutton-icon"); + stopButton.getGraphic().getStyleClass().addAll("pad-icon", "pad-stopbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-stopbutton-icon"); + newButton.getGraphic().getStyleClass().addAll("pad-icon", "pad-newbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-newbutton-icon"); + settingsButton.getGraphic().getStyleClass().addAll("pad-icon", "pad-deletebutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-settingsbutton-icon"); + + getButtonBox().getStyleClass().add("pad-button-box"); + getRoot().getStyleClass().add("pad-root"); + } + + public void removeStyleClasses(Pad pad) { + getStyleClass().removeAll("pad", "pad" + pad.getIndex()); + + indexLabel.getStyleClass().removeAll("pad-index", "pad" + pad.getIndex() + "-index", "pad-info", "pad" + pad.getIndex() + "-info"); + timeLabel.getStyleClass().removeAll("pad-time", "pad" + pad.getIndex() + "-time", "pad-info", "pad" + pad.getIndex() + "-info"); + loopLabel.getGraphic().getStyleClass().removeAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + triggerLabel.getGraphic().getStyleClass().removeAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + messageLabel.getGraphic().getStyleClass().removeAll("pad-loop", "pad" + pad.getIndex() + "-loop", "pad-icon", + "pad" + pad.getIndex() + "-icon"); + + preview.getChildren().forEach(i -> i.getStyleClass().removeAll("pad-title", "pad" + pad.getIndex() + "-title")); + + playBar.getStyleClass().removeAll("pad-playbar", "pad" + pad.getIndex() + "-playbar"); + + playButton.getStyleClass().removeAll("pad-button", "pad-playbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-playbutton"); + pauseButton.getStyleClass().removeAll("pad-button", "pad-pausebutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-pausebutton"); + stopButton.getStyleClass().removeAll("pad-button", "pad-stopbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-stopbutton"); + newButton.getStyleClass().removeAll("pad-button", "pad-newbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-newbutton"); + settingsButton.getStyleClass().removeAll("pad-button", "pad-settingsbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-settingsbutton"); + + playButton.getGraphic().getStyleClass().removeAll("pad-icon", "pad-playbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-playbutton-icon"); + pauseButton.getGraphic().getStyleClass().removeAll("pad-icon", "pad-pausebutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-pausebutton-icon"); + stopButton.getGraphic().getStyleClass().removeAll("pad-icon", "pad-stopbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-stopbutton-icon"); + newButton.getGraphic().getStyleClass().removeAll("pad-icon", "pad-newbutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-newbutton-icon"); + settingsButton.getGraphic().getStyleClass().removeAll("pad-icon", "pad-deletebutton-icon", "pad" + pad.getIndex() + "-icon", + "pad" + pad.getIndex() + "-settingsbutton-icon"); + + getButtonBox().getStyleClass().add("pad-button-box"); + getRoot().getStyleClass().add("pad-root"); + } + + public void showPlaybar(boolean b) { + if (b) { + if (!root.getChildren().contains(playBar)) + root.getChildren().add(2, playBar); + } else { + root.getChildren().remove(playBar); + } + } + + @Override + public IPadContentView getPadContentView() { + return previewContent; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/LaunchDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/LaunchDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..5ce4507fbd74551a1bf6eebab8660fe64b88b5c5 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/LaunchDialog.java @@ -0,0 +1,229 @@ +package de.tobias.playpad.viewcontroller; + +import java.io.File; +import java.nio.file.Path; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.ProfileChooseable; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectImporter; +import de.tobias.playpad.project.ProjectNotFoundException; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileNotFoundException; +import de.tobias.playpad.viewcontroller.cell.ProjectCell; +import de.tobias.playpad.viewcontroller.dialog.ImportDialog; +import de.tobias.playpad.viewcontroller.dialog.NewProjectDialog; +import de.tobias.playpad.viewcontroller.dialog.ProfileChooseDialog; +import de.tobias.utils.application.App; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseButton; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Modality; +import javafx.stage.Stage; + +public class LaunchDialog extends ViewController implements ProfileChooseable { + + private static final String IMAGE = "icon.png"; + + @FXML private Label infoLabel; + @FXML private ImageView imageView; + + @FXML private ListView<ProjectReference> projectListView; + + @FXML private Button newProfileButton; + @FXML private Button importProfileButton; + @FXML private Button openButton; + @FXML private Button deleteButton; + + public LaunchDialog(Stage stage) { + super("launchDialog", "de/tobias/playpad/assets/dialog/", stage, null, PlayPadMain.getUiResourceBundle()); + projectListView.getItems().addAll(ProjectReference.getProjectsSorted()); + } + + @Override + public void init() { + App app = ApplicationUtils.getApplication(); + infoLabel.setText(Localization.getString(Strings.UI_Dialog_Launch_Info, app.getInfo().getName(), app.getInfo().getVersion())); + try { + imageView.setImage(new Image(IMAGE)); + } catch (Exception e) { + e.printStackTrace(); + } + + openButton.setDisable(true); + deleteButton.setDisable(true); + + projectListView.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_Project))); + projectListView.setId("list"); + projectListView.setCellFactory(list -> new ProjectCell()); + + projectListView.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + openButton.setDisable(c == null); + deleteButton.setDisable(c == null); + }); + + // Mouse Double Click on list + projectListView.setOnMouseClicked(mouseEvent -> + { + if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) { + if (mouseEvent.getClickCount() == 2) { + if (!projectListView.getSelectionModel().isEmpty()) { + ProjectReference ref = projectListView.getSelectionModel().getSelectedItem(); + launchProject(ref); + } + } + } + }); + } + + @Override + public void initStage(Stage stage) { + setCSS("style.css", "de/tobias/playpad/assets/"); + setCSS("launchDialog_style.css", "de/tobias/playpad/assets/style/"); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_Launch_Title)); + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setOnCloseRequest(e -> + { + Worker.shutdown(); + }); + + stage.setResizable(false); + stage.setWidth(650); + stage.show(); + } + + @FXML + private void newProfileButtonHandler(ActionEvent event) { + NewProjectDialog dialog = new NewProjectDialog(getStage()); + dialog.getStage().showAndWait(); + + Project project = dialog.getProject(); + if (project != null) { + PlayPadMain.launchProject(project); + getStage().close(); + } + } + + @FXML + private void importProfileButtonHandler(ActionEvent event) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters() + .add(new ExtensionFilter(Localization.getString(Strings.File_Filter_ZIP), PlayPadMain.projectCompressedType)); + File file = chooser.showOpenDialog(getStage()); + if (file != null) { + Path zipFile = file.toPath(); + try { + ProjectReference ref = ProjectImporter.importProject(zipFile, ImportDialog.getInstance(getStage()), + ImportDialog.getInstance(getStage())); + if (ref != null) { + launchProject(ref); + } + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Project_Open, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + } + + @FXML + private void openButtonHandler(ActionEvent event) { + ProjectReference ref = projectListView.getSelectionModel().getSelectedItem(); + try { + if (ref != null) { + Project project = Project.load(ref, true, this); + PlayPadMain.launchProject(project); + getStage().close(); + } + } catch (ProfileNotFoundException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Profile_NotFound, ref.getProfileReference(), e.getLocalizedMessage())); + + // Neues Profile wählen + Profile profile = getUnkownProfile(); + ref.setProfileReference(profile.getRef()); + } catch (ProjectNotFoundException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Project_NotFound, ref, e.getLocalizedMessage())); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Project_Open, ref, e.getLocalizedMessage())); + } + } + + @FXML + private void deleteButtonHandler(ActionEvent event) { + if (projectListView.getSelectionModel().getSelectedItem() != null) { + ProjectReference ref = projectListView.getSelectionModel().getSelectedItem(); + + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setContentText(Localization.getString(Strings.UI_Dialog_ProjectManager_Delete_Content, ref)); + + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + + alert.showAndWait().filter(item -> item == ButtonType.OK).ifPresent(item -> + { + try { + ProjectReference.removeDocument(ref); + projectListView.getItems().remove(ref); // VIEW + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Project_Delete, e.getLocalizedMessage())); + } + }); + } + } + + private void launchProject(ProjectReference ref) { + try { + Project project = Project.load(ref, true, this); + PlayPadMain.launchProject(project); + getStage().close(); + } catch (ProfileNotFoundException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Profile_NotFound, ref.getProfileReference(), e.getLocalizedMessage())); + + // Neues Profile wählen + Profile profile = getUnkownProfile(); + ref.setProfileReference(profile.getRef()); + } catch (ProjectNotFoundException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Project_NotFound, ref, e.getLocalizedMessage())); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Project_Open, ref, e.getLocalizedMessage())); + } + } + + @Override + public Profile getUnkownProfile() { + ProfileChooseDialog dialog = new ProfileChooseDialog(getStage()); + + dialog.getStage().showAndWait(); + Profile profile = dialog.getProfile(); + if (profile != null) { + return profile; + } + return null; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/PadSettingsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/PadSettingsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..40fa82395914da4674ac45e6fe85d705a4129219 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/PadSettingsViewController.java @@ -0,0 +1,305 @@ +package de.tobias.playpad.viewcontroller; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Optional; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.midi.device.DisplayableDevice; +import de.tobias.playpad.model.layout.CartLayout; +import de.tobias.playpad.model.layout.LayoutRegistry; +import de.tobias.playpad.pad.Fade; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Pad.TimeMode; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.pad.view.PadViewController; +import de.tobias.playpad.plugin.PlayPadPlugin; +import de.tobias.playpad.plugin.viewcontroller.CartLayoutViewController; +import de.tobias.playpad.plugin.viewcontroller.IPadSettingsViewController; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.TimeModeCell; +import de.tobias.playpad.viewcontroller.settings.FadeViewController; +import de.tobias.playpad.viewcontroller.settings.WarningFeedbackViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Slider; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; +import javafx.stage.Window; + +// TODO Renew this class +public class PadSettingsViewController extends ViewController implements IPadSettingsViewController { + + @FXML private TabPane tabPane; + + @FXML private TextField titleTextField; + @FXML private Slider volumeSlider; + @FXML private CheckBox repeatCheckBox; + + @FXML private CheckBox customTimeDisplayCheckBox; + @FXML private ComboBox<TimeMode> timeDisplayComboBox; + + @FXML private CheckBox customFadeCheckBox; + @FXML private AnchorPane fadeContainer; + private FadeViewController fadeViewController; + + @FXML private AnchorPane layoutAnchorPane; + @FXML private CheckBox enableLayoutCheckBox; + private CartLayoutViewController layoutViewController; + + @FXML private AnchorPane warningFeedbackContainer; + @FXML private CheckBox warningEnableCheckBox; + + @FXML private Button deleteButton; + @FXML private Button folderButton; + @FXML private Button finishButton; + + private Pad pad; + private PadViewController controller; + + public PadSettingsViewController(Pad pad, PadViewController controller, Window owner) { + super("padSettingsView", "de/tobias/playpad/assets/settings/", null, PlayPadMain.getUiResourceBundle()); + this.pad = pad; + this.controller = controller; + + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> l.onInit(this)); + + getStage().initOwner(owner); + + titleTextField.setText(pad.getTitle()); + volumeSlider.setValue(pad.getVolume() * 100); + if (pad.isCustomFade()) + fadeViewController.setFade(pad.getFade().get()); + + repeatCheckBox.setSelected(pad.isLoop()); + + customTimeDisplayCheckBox.setSelected(pad.isCustomTimeMode()); + if (!pad.isCustomTimeMode()) { + timeDisplayComboBox.setDisable(true); + } + timeDisplayComboBox.setValue(pad.getTimeMode().orElse(TimeMode.REST)); + + customFadeCheckBox.setSelected(pad.isCustomFade()); + if (!pad.isCustomFade()) { + fadeContainer.setDisable(true); + } + + enableLayoutCheckBox.setSelected(pad.isCustomLayout()); + if (pad.isCustomLayout()) { + try { + String layoutType = Profile.currentProfile().getProfileSettings().getLayoutType(); + Optional<CartLayout> layoutOpt = pad.getLayout(layoutType); + if (layoutOpt.isPresent()) { + setLayoutController(LayoutRegistry.cartViewControllerInstance(layoutType, layoutOpt.get())); + } + } catch (Exception e) { + e.printStackTrace(); + // TODO + } + } + + warningEnableCheckBox.setSelected(pad.isCustomWarning()); + warningEnableCheckBox.selectedProperty().addListener((a, b, c) -> + { + if (c && !pad.isCustomWarning()) { + pad.setWarningFeedback(new Warning()); + addWarningController(); + } else if (b && pad.isCustomWarning()) { + pad.setWarningFeedback(null); + warningFeedbackContainer.getChildren().clear(); + } + }); + + if (pad.isCustomWarning()) { + addWarningController(); + } + + if (!pad.isPadLoaded()) + folderButton.setDisable(true); + + getStage().getScene().setOnKeyReleased(ke -> + { + if (ke.isShortcutDown() && ke.getCode() == KeyCode.W) { + Platform.runLater(() -> finishButtonHandler(null)); + } + }); + } + + private void addWarningController() { + Midi midi = Midi.getInstance(); + + ContentViewController controller = null; + if (midi.getMidiDevice().isPresent()) { + Device device = Midi.getInstance().getMidiDevice().get(); + if (device instanceof DisplayableDevice) { + controller = ((DisplayableDevice) device).getWarnViewController(pad); + } + } + + if (controller == null) { + controller = new WarningFeedbackViewController(pad); + } + + if (controller != null) { + warningFeedbackContainer.getChildren().add(controller.getParent()); + setAnchor(controller.getParent(), 0, 0, 0, 0); + } + } + + @Override + public void init() { + // Listener + titleTextField.textProperty().addListener((a, b, c) -> pad.setTitle(c)); + + // Embed ViewController + fadeViewController = new FadeViewController(); + fadeContainer.getChildren().add(fadeViewController.getParent()); + setAnchor(fadeViewController.getParent(), 0.0, 0.0, 0.0, 0.0); + + volumeSlider.valueProperty().addListener((a, b, c) -> pad.setVolume(c.doubleValue() / 100.0)); + repeatCheckBox.selectedProperty().addListener((a, b, c) -> + { + pad.setLoop(c); + if (controller != null) + controller.getView().setLoopLabelActive(c); + }); + + customTimeDisplayCheckBox.selectedProperty().addListener((a, b, c) -> + { + timeDisplayComboBox.setDisable(!c); + if (c && !pad.isCustomTimeMode()) + pad.setTimeMode(TimeMode.REST); + else if (b && pad.isCustomTimeMode()) + pad.setTimeMode(null); + + }); + timeDisplayComboBox.getItems().addAll(TimeMode.values()); + timeDisplayComboBox.valueProperty().addListener((a, b, c) -> + { + pad.setTimeMode(c); + }); + timeDisplayComboBox.setButtonCell(new TimeModeCell()); + timeDisplayComboBox.setCellFactory(list -> new TimeModeCell()); + + customFadeCheckBox.selectedProperty().addListener((a, b, c) -> + { + fadeContainer.setDisable(!c); + if (c && !pad.isCustomFade()) + pad.setFade(new Fade()); + else if (!c && pad.isCustomFade()) + pad.setFade(null); + + if (c) + fadeViewController.setFade(pad.getFade().get()); + }); + + enableLayoutCheckBox.selectedProperty().addListener((a, b, c) -> + { + if (c && !pad.isCustomLayout()) { + try { + pad.setCustomLayout(true); + try { + String layoutType = Profile.currentProfile().getProfileSettings().getLayoutType(); + Optional<CartLayout> layoutOpt = pad.getLayout(layoutType); + if (layoutOpt.isPresent()) { + setLayoutController(LayoutRegistry.cartViewControllerInstance(layoutType, layoutOpt.get())); + } + } catch (Exception e) { + e.printStackTrace(); + // TODO + } + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Standard_Gen, e.getLocalizedMessage())); + e.printStackTrace(); + } + } else if (!c && pad.isCustomLayout()) { + pad.setCustomLayout(false); + setLayoutController(null); + } + }); + } + + private void setLayoutController(CartLayoutViewController cartLayoutViewController) { + if (layoutViewController != null) + layoutAnchorPane.getChildren().remove(layoutViewController.getParent()); + + if (cartLayoutViewController != null) { + layoutViewController = cartLayoutViewController; + layoutAnchorPane.getChildren().add(layoutViewController.getParent()); + setAnchor(layoutViewController.getParent(), 0, 0, 0, 0); + } + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(650); + stage.setMinHeight(530); + stage.setTitle(Localization.getString(Strings.UI_Window_PadSettings_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void deleteButtonHandler(ActionEvent event) { + pad.clearPad(); + getStage().close(); + } + + @Override + public boolean closeRequest() { + if (layoutViewController != null) { + layoutViewController.save(); + } + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> l.onClose(this)); + return true; + } + + @FXML + private void folderButtonHandler(ActionEvent event) { + try { + Desktop.getDesktop().open(pad.getPath().toFile().getParentFile()); + } catch (IOException | URISyntaxException e) { + showErrorMessage(Localization.getString(Strings.Error_Standard_Gen, e.getMessage()), PlayPadMain.stageIcon); + e.printStackTrace(); + } + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + if (layoutViewController != null) { + layoutViewController.save(); + } + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> l.onClose(this)); + getStage().close(); + } + + public Pad getPad() { + return pad; + } + + public void addTab(String name, AnchorPane content) { + content.setMinSize(0, 0); + content.setMaxSize(AnchorPane.USE_COMPUTED_SIZE, AnchorPane.USE_COMPUTED_SIZE); + tabPane.getTabs().add(new Tab(name, content)); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/PluginViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/PluginViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..d7c5c2392c56c19f44221a126ade41210ebb54be --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/PluginViewController.java @@ -0,0 +1,111 @@ +package de.tobias.playpad.viewcontroller; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import de.tobias.playpad.AppUserInfoStrings; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.plugin.Plugin; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.PluginCell; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; +import net.xeoh.plugins.base.PluginManager; + +public class PluginViewController extends ViewController { + + @FXML private ListView<Plugin> pluginListView; + @FXML private Button finishButton; + + private PluginManager manager; + + public PluginViewController(PluginManager manager, Window owner) { + super("pluginView", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + this.manager = manager; + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + Worker.runLater(() -> + { + try { + List<Plugin> plugins = new ArrayList<>(); + + URL url = new URL(ApplicationUtils.getApplication().getInfo().getUserInfo().getString(AppUserInfoStrings.PLUGINS_URL)); + FileConfiguration cfg = YamlConfiguration.loadConfiguration(url.openStream()); + + // Iterate over all plugins that are online avialable + for (String key : cfg.getConfigurationSection("plugins").getKeys(false)) { + String name = cfg.getString("plugins." + key + ".name"); + String pluginUrl = cfg.getString("plugins." + key + ".url"); + String fileName = cfg.getString("plugins." + key + ".filename"); + boolean active = false; + + try { + Path path = ApplicationUtils.getApplication().getPath(PathType.LIBRARY, fileName); + if (Files.exists(path)) + active = true; + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Plugins_Download, name), PlayPadMain.stageIcon); + } + + Plugin plugin = new Plugin(name, fileName, pluginUrl, active); + plugins.add(plugin); + } + + Collections.sort(plugins, (o1, o2) -> o1.getName().compareTo(o2.getName())); + pluginListView.getItems().addAll(plugins); + } catch (IOException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Standard_Gen), PlayPadMain.stageIcon); + } + }); + } + + @Override + public void init() { + pluginListView.setCellFactory(list -> new PluginCell(manager)); + pluginListView.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_Plugins))); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(550); + stage.setMaxWidth(550); + stage.setMinHeight(500); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_Plugins_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + getStage().close(); + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/PresetsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/PresetsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..27ce636e43cbf202d9cbb3b871b47ae8afcdfa71 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/PresetsViewController.java @@ -0,0 +1,388 @@ +package de.tobias.playpad.viewcontroller; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.settings.MidiPreset; +import de.tobias.playpad.settings.MidiSettings; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.PresetCell; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.ui.scene.NotificationPane; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import javafx.scene.layout.AnchorPane; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class PresetsViewController extends ViewController implements NotificationHandler { + + @FXML private AnchorPane presetsContainer; + @FXML private AnchorPane presetsAnchorPane; + + @FXML private ListView<MidiPreset> presetsListView; + + @FXML private TextField nameTextField; + @FXML private CheckBox partlyCheckBox; + @FXML private CheckBox activeCheckBox; + @FXML private TextField pageTextField; + + @FXML private Button addButton; + @FXML private Button removeButton; + @FXML private Button importButton; + @FXML private Button exportButton; + @FXML private Button duplicateButton; + @FXML private Button defaultButton; + + @FXML private Button finishButton; + + private NotificationPane notificationPane; + private MidiSettings midiSettings; + + public PresetsViewController(Window window) { + super("presetsView", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + getStage().initOwner(window); + + presetsListView.setItems(midiSettings.getPresets()); + for (MidiPreset preset : midiSettings.getPresets()) { + if (preset.isActive()) { + presetsListView.getSelectionModel().select(preset); + break; + } + } + + if (midiSettings.getPresets().size() == 1) { + removeButton.setDisable(true); + } + } + + @Override + public void init() { + notificationPane = new NotificationPane(presetsAnchorPane); + notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK); + presetsContainer.getChildren().add(notificationPane); + setAnchor(notificationPane, 0, 0, 0, 0); + + presetsListView.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_Preset))); + + // Ausgewählte in der Liste rechts zeigen und Button disablen + presetsListView.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + showPreset(c); + if (c == null) { + exportButton.setDisable(true); + if (midiSettings.getPresets().size() <= 1) + removeButton.setDisable(true); + } else { + removeButton.setDisable(false); + exportButton.setDisable(false); + } + }); + + // Name des Presets aktualisieren + nameTextField.textProperty().addListener((a, b, c) -> + { + MidiPreset item = getSelectedMidiPreset(); + if (item != null) { + item.setName(c); + } + }); + + activeCheckBox.selectedProperty().addListener((a, b, c) -> + { + MidiPreset preset = getSelectedMidiPreset(); + if (c) { + disableInvalidPresets(true, getSelectedMidiPreset(), midiSettings); + } + if (preset != null) { + preset.setActive(c); + } + }); + + partlyCheckBox.selectedProperty().addListener((a, b, c) -> + { + MidiPreset item = getSelectedMidiPreset(); + if (item != null) { + item.setPartly(c); + } + }); + + pageTextField.textProperty().addListener((a, b, c) -> + { + MidiPreset preset = getSelectedMidiPreset(); + if (preset != null) { + // Model Update + if (c.isEmpty()) { + preset.setPage(-1); + } else { + try { + int page = Integer.valueOf(c) - 1; + preset.setPage(page); + pageTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + } catch (NumberFormatException e) { + pageTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + } + + // Kollision zeigen + if (preset.isActive()) { + disableInvalidPresets(false, getSelectedMidiPreset(), midiSettings); + } + } + }); + + presetsListView.setCellFactory(item -> new PresetCell()); + + getStage().getScene().getAccelerators().put(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN), + () -> Platform.runLater(() -> getStage().close())); + } + + public static List<MidiPreset> disableInvalidPresets(boolean disable, MidiPreset preset, MidiSettings midiSettings) { + List<MidiPreset> disabledPresets = new ArrayList<>(); + + // Neues Preset ist Global -> alle anderen weg + if (preset.getPage() == -1) { + for (MidiPreset item : midiSettings.getPresets()) { + if (item != preset) { + if (item.isActive()) { + if (disable) { + item.setActive(false); + } + disabledPresets.add(item); + } + } + } + } else { + for (MidiPreset item : midiSettings.getPresets()) { + if (item != preset) { + if (item.isActive() && item.getPage() == -1 || item.isActive() && item.getPage() == preset.getPage()) { + if (disable) { + item.setActive(false); + } + disabledPresets.add(item); + } + } + } + } + return disabledPresets; + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(600); + stage.setMinHeight(400); + stage.setTitle(Localization.getString(Strings.UI_Dialog_Preset_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + private void showPreset(MidiPreset midiPreset) { + if (midiPreset != null) { + nameTextField.setText(midiPreset.getName()); + activeCheckBox.setSelected(midiPreset.isActive()); + partlyCheckBox.setSelected(midiPreset.isPartly()); + if (midiPreset.getPage() != -1) { + pageTextField.setText(String.valueOf(midiPreset.getPage() + 1)); + } else { + pageTextField.clear(); + } + activeCheckBox.setDisable(false); + partlyCheckBox.setDisable(false); + } else { + nameTextField.setText(null); + activeCheckBox.setSelected(false); + partlyCheckBox.setSelected(false); + pageTextField.clear(); + activeCheckBox.setDisable(true); + partlyCheckBox.setDisable(true); + } + } + + @FXML + private void addButtonHandler(ActionEvent event) { + MidiPreset preset = new MidiPreset(); + midiSettings.getPresets().add(preset); + if (midiSettings.getPresets().size() > 1) { + removeButton.setDisable(false); + } + presetsListView.getSelectionModel().select(preset); + } + + @FXML + private void removeButtonHandler(ActionEvent event) { + midiSettings.getPresets().remove(presetsListView.getSelectionModel().getSelectedIndex()); + if (midiSettings.getPresets().size() == 1) { + removeButton.setDisable(true); + } + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void importButtonHandler(ActionEvent event) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters().add(new ExtensionFilter(Localization.getString(Strings.File_Filter_Preset), PlayPadMain.midiPresetType)); + File file = chooser.showOpenDialog(getStage()); + if (file != null) { + Path path = file.toPath(); + + Worker.runLater(() -> + { + try { + MidiPreset preset = midiSettings.importMidiPreset(path); + preset.setActive(false); // DEFAULT nicht Active + Platform.runLater(() -> + { + if (midiSettings.getPresets().size() == 1) { + removeButton.setDisable(true); + } else { + removeButton.setDisable(false); + } + + notify(Localization.getString(Strings.Standard_File_Save), PlayPadMain.notificationDisplayTimeMillis); + }); + + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Preset_Import, e.getLocalizedMessage())); + } + }); + } + } + + @FXML + private void exportButtonHandler(ActionEvent event) { + MidiPreset preset = getSelectedMidiPreset(); + if (preset != null) { + FileChooser chooser = new FileChooser(); + + ExtensionFilter filter = new ExtensionFilter(Localization.getString(Strings.File_Filter_Preset), PlayPadMain.midiPresetType); + chooser.getExtensionFilters().add(filter); + + File file = chooser.showSaveDialog(getStage()); + if (file != null) { + Path path = file.toPath(); + + Worker.runLater(() -> + { + try { + midiSettings.exportMidiPreset(path, preset); + notify(Localization.getString(Strings.Standard_File_Save), PlayPadMain.notificationDisplayTimeMillis); + } catch (IOException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Preset_Export, e.getLocalizedMessage())); + } + }); + } + } + } + + private MidiPreset getSelectedMidiPreset() { + return presetsListView.getSelectionModel().getSelectedItem(); + } + + @FXML + private void duplicateButtonHandler() { + MidiPreset preset = getSelectedMidiPreset(); + try { + MidiPreset preset2 = preset.clone(); + preset2.setName(Localization.getString(Strings.Standard_Copy, preset2.getName())); + preset2.setActive(false); + +// Profile.currentProfile().getMidiSetting().getPresets().add(preset2); + presetsListView.getSelectionModel().select(preset2); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + } + + @FXML + private void defaultButtonHandler() { + Alert alert = new Alert(AlertType.CONFIRMATION); + + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + + alert.setContentText(Localization.getString(Strings.Info_Settings_Preset_RestoreDefaults)); + alert.showAndWait().filter(button -> button == ButtonType.OK).ifPresent(button -> + { + try { + Path path = ApplicationUtils.getApplication().getPath(PathType.CONFIGURATION, Profile.currentProfile().getName(), "Midi.xml"); + midiSettings.createDefaultSettings(path); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Preset_RestoreDefaults, e.getLocalizedMessage())); + } + }); + } + + // UI Info + @Override + public void notify(String text, long duration) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration)); + } + } + + @Override + public void notify(String text, long duration, Runnable finish) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration, finish); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration, finish)); + } + } + + @Override + public void showError(String message) { + if (Platform.isFxApplicationThread()) { + notificationPane.showError(message); + } else { + Platform.runLater(() -> notificationPane.showError(message)); + } + } + + @Override + public void hide() { + if (Platform.isFxApplicationThread()) { + notificationPane.hide(); + } else { + Platform.runLater(() -> notificationPane.hide()); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/PrintDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/PrintDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..4b88bd8e0cdcbdd10d5c9f5de79ba57e85432bcf --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/PrintDialog.java @@ -0,0 +1,142 @@ +package de.tobias.playpad.viewcontroller; + +import com.hp.gagawa.java.elements.Body; +import com.hp.gagawa.java.elements.Div; +import com.hp.gagawa.java.elements.H1; +import com.hp.gagawa.java.elements.Html; +import com.hp.gagawa.java.elements.Table; +import com.hp.gagawa.java.elements.Td; +import com.hp.gagawa.java.elements.Tr; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.print.PageLayout; +import javafx.print.PageOrientation; +import javafx.print.Paper; +import javafx.print.Printer; +import javafx.print.Printer.MarginType; +import javafx.print.PrinterJob; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class PrintDialog extends ViewController { + + @FXML private WebView webView; + @FXML private ComboBox<Integer> pageComboBox; + @FXML private Button printButton; + @FXML private Button cancelButton; + + private Project project; + + public PrintDialog(Project project, Window owner) { + super("printDialog", "de/tobias/playpad/assets/dialog/project/", null, PlayPadMain.getUiResourceBundle()); + this.project = project; + + pageComboBox.getSelectionModel().selectFirst(); + + getStage().initOwner(owner); + } + + @Override + public void init() { + int pages = Profile.currentProfile().getProfileSettings().getPageCount(); + for (int i = 0; i < pages; i++) { + pageComboBox.getItems().add(i + 1); + } + + pageComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + createPreview(c - 1); + }); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(600); + stage.setMinHeight(400); + stage.setTitle(Localization.getString(Strings.UI_Dialog_Print_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + private void createPreview(int page) { + Html html = new Html(); + Body body = new Body(); + body.setStyle("max-width: 1000px; font-family: sans-serif;"); + html.appendChild(body); + + H1 header = new H1(); + + String headerString = Localization.getString(Strings.Info_Print_Header, project.getRef().getName(), page + 1); + header.appendText(headerString); + header.setStyle("text-align: center;"); + body.appendChild(header); + + Table table = new Table(); + table.setStyle("border:1px solid black;border-collapse:collapse;"); + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + + int i = page * profilSettings.getRows() * profilSettings.getColumns(); + + for (int y = 0; y < profilSettings.getRows(); y++) { + Tr tr = new Tr(); + table.appendChild(tr); + for (int x = 0; x < profilSettings.getColumns(); x++) { + Td td = new Td(); + td.setStyle("border:1px solid black; width: " + 1000 / (float) profilSettings.getColumns() + + "px; padding: 5px; vertical-align: center; text-align: center; min-height: 30px; min-width: 100px;"); + Div div = new Div(); + div.setStyle("word-break: break-all; white-space: normal;"); + Pad pad = this.project.getPad(i); + + if (pad.getContent() != null && pad.getContent().isPadLoaded()) + div.appendText(pad.getName()); + else + div.appendText("-"); + td.appendChild(div); + i++; + tr.appendChild(td); + } + } + body.appendChild(table); + WebEngine e = webView.getEngine(); + e.loadContent(html.write()); + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void printButtonHandler(ActionEvent event) { + Printer printer = Printer.getDefaultPrinter(); + PageLayout layout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, MarginType.DEFAULT); + PrinterJob job = PrinterJob.createPrinterJob(printer); + job.getJobSettings().setPageLayout(layout); + job.getJobSettings().setJobName(ApplicationUtils.getApplication().getInfo().getName()); + if (job != null && job.showPrintDialog(getStage())) { + webView.getEngine().print(job); + job.endJob(); + getStage().close(); + } + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..020656123627b651bbaab676ba9bb2f41cecc0c5 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionViewController.java @@ -0,0 +1,77 @@ +package de.tobias.playpad.viewcontroller.actions; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.cartaction.CartAction.ControlMode; +import de.tobias.playpad.action.mapper.MapperRegistry; +import de.tobias.playpad.action.mapper.MapperViewController; +import de.tobias.playpad.viewcontroller.IMapperOverviewViewController; +import de.tobias.playpad.viewcontroller.cell.EnumCell; +import de.tobias.utils.ui.ContentViewController; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +public class CartActionViewController extends ContentViewController { + + @FXML private ComboBox<ControlMode> controlMode; + @FXML private CheckBox autoColorCheckbox; + + @FXML private VBox rootContainer; + private IMapperOverviewViewController mapperOverviewViewController; + + private CartAction action; + + public CartActionViewController() { + super("cartAction", "de/tobias/playpad/assets/view/actions/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public void init() { + controlMode.getItems().setAll(ControlMode.values()); + controlMode.setCellFactory(list -> new EnumCell<>(Strings.CartAction_Mode_BaseName)); + controlMode.setButtonCell(new EnumCell<>(Strings.CartAction_Mode_BaseName)); + controlMode.valueProperty().addListener((a, b, c) -> + { + action.setMode(c); + }); + + autoColorCheckbox.selectedProperty().addListener((a, b, c) -> + { + action.setAutoFeedbackColors(c); + // Disable Feedback Controls bei Automatischen Feedback für VORHANDENE MAPPER + if (mapperOverviewViewController != null) { + mapperOverviewViewController.getControllers().forEach(controller -> + { + toggleFeedbackVisablity(action, controller); + }); + } + }); + VBox.setVgrow(rootContainer, Priority.ALWAYS); + + mapperOverviewViewController = MapperRegistry.getOverviewViewControllerInstance(); + mapperOverviewViewController.addMapperAddListener((mapper, controller) -> + { + // Disable Feedback Controls bei Automatischen Feedback für NEUE MAPPER die erstellt werden + toggleFeedbackVisablity(action, controller); + }); + } + + public void setCartAction(CartAction action) { + this.action = action; + + controlMode.setValue(action.getMode()); + autoColorCheckbox.setSelected(action.isAutoFeedbackColors()); + } + + private void toggleFeedbackVisablity(CartAction action, MapperViewController controller) { + if (action.isAutoFeedbackColors()) { + controller.hideFeedback(); + } else { + controller.showFeedback(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..6b559d479ee894aca9cf5b6c7a4b9455c264b1f6 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/actions/CartActionsViewController.java @@ -0,0 +1,136 @@ +package de.tobias.playpad.viewcontroller.actions; + +import java.util.List; + +import org.controlsfx.control.SegmentedButton; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.connect.CartActionConnect; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.IMappingTabViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.RowConstraints; +import javafx.scene.layout.VBox; + +/** + * Diese View ist die Basis für die Einstellunge für eine CartAction. Dabei enthällt diese View ein Grid aus Buttons (Carts), eine + * seitenauswahl (Carts ändern sich) und eine Scrollview für die Einstellungen. Die Einstellungen werden von der Class + * CartActionViewController hier eingebettet. Dabei wird nicht jedes mal eine neue Instance erstellt, sondern die in CartAction vorhandene + * Instance verwendet. Das geht, solange die View nur einmal verwendet wird. + * + * @author tobias + * + */ +public class CartActionsViewController extends ContentViewController { + + @FXML private VBox buttonVbox; + @FXML private HBox pageHbox; + + private ToggleGroup cartsToggle; + @FXML private GridPane gridPane; + + @FXML private VBox cartActionContainer; + + private Mapping mapping; + private IMappingTabViewController parentController; + + public CartActionsViewController(Mapping mapping, IMappingTabViewController parentController) { + super("cartActions", "de/tobias/playpad/assets/view/actions/", PlayPadMain.getUiResourceBundle()); + this.mapping = mapping; + this.parentController = parentController; + + ProfileSettings settings = Profile.currentProfile().getProfileSettings(); + + showCartButtons(settings, 0); + VBox.setVgrow(gridPane, Priority.ALWAYS); + + SegmentedButton segmentedButton = new SegmentedButton(); + for (int i = 0; i < settings.getPageCount(); i++) { + ToggleButton button = new ToggleButton(Localization.getString(Strings.UI_Window_Main_PageButton, i + 1)); + button.setOnAction(e -> + { + int page = Integer.valueOf(((ToggleButton) e.getSource()).getUserData().toString()); + showCartButtons(Profile.currentProfile().getProfileSettings(), page); + }); + button.setUserData(i); + segmentedButton.getButtons().add(button); + } + segmentedButton.getStyleClass().add(SegmentedButton.STYLE_CLASS_DARK); + pageHbox.getChildren().add(segmentedButton); + segmentedButton.getButtons().get(0).setSelected(true); // Select First Toggle + } + + @Override + public void init() { + buttonVbox.minHeightProperty().bind(buttonVbox.heightProperty()); + } + + private void showCartButtons(ProfileSettings settings, int page) { + gridPane.getChildren().clear(); + + gridPane.getColumnConstraints().clear(); + double xPercentage = 1.0 / (double) settings.getColumns(); + for (int i = 0; i < settings.getColumns(); i++) { + ColumnConstraints c = new ColumnConstraints(); + c.setPercentWidth(xPercentage * 100); + gridPane.getColumnConstraints().add(c); + } + + gridPane.getRowConstraints().clear(); + double yPercentage = 1.0 / (double) settings.getRows(); + for (int i = 0; i < settings.getRows(); i++) { + RowConstraints c = new RowConstraints(); + c.setPercentHeight(yPercentage * 100); + gridPane.getRowConstraints().add(c); + } + + cartsToggle = new ToggleGroup(); + + int startValue = (page * settings.getColumns() * settings.getRows()); + + for (int x = 0; x < settings.getColumns(); x++) { + for (int y = 0; y < settings.getRows(); y++) { + int index = (settings.getColumns() * y + x) + startValue; + ToggleButton button = new ToggleButton(String.valueOf(index + 1)); + button.setMaxWidth(Double.MAX_VALUE); + button.setUserData(index); + button.getStyleClass().add(SegmentedButton.STYLE_CLASS_DARK); + + // Show the right cart settings + button.selectedProperty().addListener((a, b, c) -> + { + if (c) { + int id = Integer.valueOf(button.getUserData().toString()); + + List<CartAction> cartActions = mapping.getActions(CartActionConnect.TYPE); + for (CartAction action : cartActions) { + if (action.getCart() == id) { + ContentViewController actionViewController = action.getSettingsViewController(); + cartActionContainer.getChildren().setAll(actionViewController.getParent()); + cartActionContainer.setVisible(true); + parentController.showMapperFor(action); + } + } + } else { + cartActionContainer.setVisible(false); + parentController.showMapperFor(null); + } + }); + gridPane.add(button, x, y); + cartsToggle.getToggles().add(button); + } + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/audio/ClipSettingsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/audio/ClipSettingsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..624d6c557b49d8606a58b71d5af1a82d0c29d919 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/audio/ClipSettingsViewController.java @@ -0,0 +1,140 @@ +package de.tobias.playpad.viewcontroller.audio; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer.Info; +import javax.sound.sampled.UnsupportedAudioFileException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.audio.TinyAudioHandler; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Worker; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.util.Callback; + +public class ClipSettingsViewController extends AudioTypeViewController implements Callback<ListView<Info>, ListCell<Info>> { + + @FXML private ComboBox<Info> soundCardComboBox; + @FXML private Button testButton; + + private boolean isChanged; + + private Clip clip; + + public ClipSettingsViewController() { + super("clipSettings", "de/tobias/playpad/assets/view/audio/", PlayPadMain.getUiResourceBundle()); + + // Mixer (ohne Port) + List<Info> infos = Arrays.stream(AudioSystem.getMixerInfo()).filter(info -> !info.getName().startsWith("Port")) + .collect(Collectors.toList()); + + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + + soundCardComboBox.getItems().setAll(infos); + soundCardComboBox.setCellFactory(this); + soundCardComboBox.setButtonCell(call(null)); + + String name = (String) Profile.currentProfile().getProfileSettings().getAudioUserInfo().get(TinyAudioHandler.SOUND_CARD); + for (Info info : AudioSystem.getMixerInfo()) { + if (info.getName().equals(name)) { + soundCardComboBox.getSelectionModel().select(info); + break; + } + } + + // ersten Auswählen wenn keiner ausgewählt ist, damit keine Probleme auftreten da keiene Soundkarte ausgewäht ist + if (soundCardComboBox.getSelectionModel().getSelectedItem() == null) { + soundCardComboBox.getSelectionModel().selectFirst(); + } + + soundCardComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + if (clip != null) { + clip.stop(); + clip = null; + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + } + + isChanged = true; + Profile.currentProfile().getProfileSettings().getAudioUserInfo().put(TinyAudioHandler.SOUND_CARD, c.getName()); + }); + } + + @FXML + private void testButtonHandler(ActionEvent event) { + try { + AudioInputStream audioIn = AudioSystem.getAudioInputStream( + ClipSettingsViewController.class.getClassLoader().getResource("de/tobias/playpad/assets/files/Test-Sound.wav")); + + if (clip != null) { + clip.stop(); + clip = null; + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + } else { + + clip = AudioSystem.getClip(soundCardComboBox.getValue()); + + clip.open(audioIn); + clip.start(); + Worker.runLater(() -> + { + while (true) { + if (clip != null) { + return; + } + if (!clip.isRunning()) { + clip.drain(); + clip.close(); + break; + } + try { + Thread.sleep(100); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + testButton.setGraphic(new FontIcon(FontAwesomeType.STOP)); + } + + } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) { + e.printStackTrace(); + } + } + + @Override + public ListCell<Info> call(ListView<Info> param) { + return new ListCell<Info>() { + + @Override + protected void updateItem(Info item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + setText(item.getName()); + } else { + setText(""); + } + } + }; + } + + @Override + public boolean isChanged() { + return isChanged; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/audio/TinySoundSettingsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/audio/TinySoundSettingsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..4429ba72ad6c5bc5b937e314e491e1248bdb7c19 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/audio/TinySoundSettingsViewController.java @@ -0,0 +1,140 @@ +package de.tobias.playpad.viewcontroller.audio; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer.Info; +import javax.sound.sampled.UnsupportedAudioFileException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.audio.TinyAudioHandler; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Worker; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.util.Callback; + +public class TinySoundSettingsViewController extends AudioTypeViewController implements Callback<ListView<Info>, ListCell<Info>> { + + @FXML private ComboBox<Info> soundCardComboBox; + @FXML private Button testButton; + + private boolean isChanged; + + private Clip clip; + + public TinySoundSettingsViewController() { + super("tinySoundSettings", "de/tobias/playpad/assets/view/audio/", PlayPadMain.getUiResourceBundle()); + + // Mixer (ohne Port) + List<Info> infos = Arrays.stream(AudioSystem.getMixerInfo()).filter(info -> !info.getName().startsWith("Port")) + .collect(Collectors.toList()); + + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + + soundCardComboBox.getItems().setAll(infos); + soundCardComboBox.setCellFactory(this); + soundCardComboBox.setButtonCell(call(null)); + + String name = (String) Profile.currentProfile().getProfileSettings().getAudioUserInfo().get(TinyAudioHandler.SOUND_CARD); + for (Info info : AudioSystem.getMixerInfo()) { + if (info.getName().equals(name)) { + soundCardComboBox.getSelectionModel().select(info); + break; + } + } + + // ersten Auswählen wenn keiner ausgewählt ist, damit keine Probleme auftreten da keiene Soundkarte ausgewäht ist + if (soundCardComboBox.getSelectionModel().getSelectedItem() == null) { + soundCardComboBox.getSelectionModel().selectFirst(); + } + + soundCardComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + if (clip != null) { + clip.stop(); + clip = null; + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + } + + isChanged = true; + Profile.currentProfile().getProfileSettings().getAudioUserInfo().put(TinyAudioHandler.SOUND_CARD, c.getName()); + }); + } + + @FXML + private void testButtonHandler(ActionEvent event) { + try { + AudioInputStream audioIn = AudioSystem.getAudioInputStream( + TinySoundSettingsViewController.class.getClassLoader().getResource("de/tobias/playpad/assets/files/Test-Sound.wav")); + + if (clip != null) { + clip.stop(); + clip = null; + testButton.setGraphic(new FontIcon(FontAwesomeType.PLAY)); + } else { + + clip = AudioSystem.getClip(soundCardComboBox.getValue()); + + clip.open(audioIn); + clip.start(); + Worker.runLater(() -> + { + while (true) { + if (clip != null) { + return; + } + if (!clip.isRunning()) { + clip.drain(); + clip.close(); + break; + } + try { + Thread.sleep(100); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + testButton.setGraphic(new FontIcon(FontAwesomeType.STOP)); + } + + } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) { + e.printStackTrace(); + } + } + + @Override + public ListCell<Info> call(ListView<Info> param) { + return new ListCell<Info>() { + + @Override + protected void updateItem(Info item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + setText(item.getName()); + } else { + setText(""); + } + } + }; + } + + @Override + public boolean isChanged() { + return isChanged; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableCell.java new file mode 100644 index 0000000000000000000000000000000000000000..69045785485c04dd624aebf5866d4391a2d707a6 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableCell.java @@ -0,0 +1,30 @@ +package de.tobias.playpad.viewcontroller.cell; + +import de.tobias.playpad.Displayable; +import javafx.scene.Node; +import javafx.scene.control.ListCell; + +public class DisplayableCell<T extends Displayable> extends ListCell<T> { + + private Displayable action; + + @Override + protected void updateItem(T action, boolean empty) { + super.updateItem(action, empty); + if (!empty) { + if (this.action == null || this.action != action) { + Node graphics = action.getGraphics(); + setGraphic(graphics); + + textProperty().bind(action.displayProperty()); + this.action = action; + } + } else { + this.action = null; + textProperty().unbind(); + + setGraphic(null); + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableTreeCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableTreeCell.java new file mode 100644 index 0000000000000000000000000000000000000000..dd11f91ca4ad5dc09570ac44132a96b4adb84e06 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/DisplayableTreeCell.java @@ -0,0 +1,30 @@ +package de.tobias.playpad.viewcontroller.cell; + +import de.tobias.playpad.Displayable; +import javafx.scene.Node; +import javafx.scene.control.TreeCell; + +public class DisplayableTreeCell<T extends Displayable> extends TreeCell<T> { + + private Displayable action; + + @Override + protected void updateItem(T action, boolean empty) { + super.updateItem(action, empty); + if (!empty) { + if (this.action == null || this.action != action) { + Node graphics = action.getGraphics(); + setGraphic(graphics); + + textProperty().bind(action.displayProperty()); + this.action = action; + } + } else { + this.action = null; + textProperty().unbind(); + + setGraphic(null); + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/EnumCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/EnumCell.java new file mode 100644 index 0000000000000000000000000000000000000000..788b5fc9f1c1307031b1b2ee5dea0d9204e1902d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/EnumCell.java @@ -0,0 +1,23 @@ +package de.tobias.playpad.viewcontroller.cell; + +import de.tobias.utils.util.Localization; +import javafx.scene.control.ListCell; + +public class EnumCell<T extends Enum<?>> extends ListCell<T> { + + private String baseName; + + public EnumCell(String baseName) { + this.baseName = baseName; + } + + @Override + protected void updateItem(T item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + setText(Localization.getString(baseName + item.name())); + } else { + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/PluginCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/PluginCell.java new file mode 100644 index 0000000000000000000000000000000000000000..b1ea5a801ab150ac7a2ceef4194d96c8f5a871e4 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/PluginCell.java @@ -0,0 +1,73 @@ +package de.tobias.playpad.viewcontroller.cell; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.plugin.Plugin; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.geometry.Pos; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ListCell; +import javafx.scene.layout.HBox; +import net.xeoh.plugins.base.PluginManager; + +public class PluginCell extends ListCell<Plugin> implements ChangeListener<Boolean> { + + private Plugin plugin; + private HBox buttons; + private CheckBox checkBox; + + private PluginManager manager; + + public PluginCell(PluginManager manager) { + this.manager = manager; + + checkBox = new CheckBox(); + checkBox.selectedProperty().addListener(this); + + buttons = new HBox(checkBox); + buttons.setSpacing(14); + buttons.setAlignment(Pos.CENTER_LEFT); + } + + @Override + protected void updateItem(Plugin item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + this.plugin = item; + if (item.isActive()) { + checkBox.setSelected(true); + } else { + checkBox.setSelected(false); + } + setGraphic(buttons); + checkBox.setText(item.getName()); + } else { + setGraphic(null); + } + } + + @Override + public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { + Path path = ApplicationUtils.getApplication().getPath(PathType.LIBRARY, plugin.getFileName()); + if (newValue) { // Wurde Aktiviert + if (Files.notExists(path)) { + try { + Files.createDirectories(path.getParent()); + Files.copy(new URL(plugin.getUrl()).openStream(), path); + } catch (IOException e) { + e.printStackTrace(); + } + } + manager.addPluginsFrom(path.toUri()); + } else { + PlayPadMain.addDeletedPlugin(path); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ProjectCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ProjectCell.java new file mode 100644 index 0000000000000000000000000000000000000000..5ee0a1ee42ca3a96948d1f22d28c7694e7c18d15 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ProjectCell.java @@ -0,0 +1,44 @@ +package de.tobias.playpad.viewcontroller.cell; + +import java.nio.file.Files; +import java.nio.file.Path; + +import de.tobias.playpad.Displayable; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.ListCell; +import javafx.scene.paint.Color; + +public class ProjectCell extends ListCell<ProjectReference> { + + private Displayable action; + + @Override + protected void updateItem(ProjectReference action, boolean empty) { + super.updateItem(action, empty); + if (!empty) { + if (this.action == null || this.action != action) { + Path path = ApplicationUtils.getApplication().getPath(PathType.DOCUMENTS, action.getFileName()); + if (Files.notExists(path)) { + FontIcon graphics = new FontIcon(FontAwesomeType.WARNING); + graphics.setColor(Color.RED); + setGraphic(graphics); + } + setContentDisplay(ContentDisplay.RIGHT); + + textProperty().bind(action.displayProperty()); + this.action = action; + } + } else { + this.action = null; + textProperty().unbind(); + + setGraphic(null); + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ThemeCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ThemeCell.java new file mode 100644 index 0000000000000000000000000000000000000000..64cdd06b4cd2fc28efc3f790c720ea428bad01b6 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/ThemeCell.java @@ -0,0 +1,19 @@ +package de.tobias.playpad.viewcontroller.cell; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.classic.Theme; +import de.tobias.utils.util.Localization; +import javafx.scene.control.ListCell; + +public class ThemeCell extends ListCell<Theme> { + + @Override + protected void updateItem(Theme item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + setText(Localization.getString(Strings.UI_Layout_Classic_Theme_BaseName + item.name())); + } else { + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/UpdateCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/UpdateCell.java new file mode 100644 index 0000000000000000000000000000000000000000..48d27b4b90eba7e5e6e99885433f76cb0fd6494e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/UpdateCell.java @@ -0,0 +1,19 @@ +package de.tobias.playpad.viewcontroller.cell; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.Updatable; +import de.tobias.utils.util.Localization; +import javafx.scene.control.ListCell; + +public class UpdateCell extends ListCell<Updatable> { + + @Override + protected void updateItem(Updatable item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + setText(Localization.getString(Strings.UI_Dialog_Update_Cell, item.name(), item.getCurrentVersion(), item.getNewVersion())); + } else { + setText(""); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/ErrorCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/ErrorCell.java new file mode 100644 index 0000000000000000000000000000000000000000..601212b6d9566e905d331b046322e06bdac4e26d --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/ErrorCell.java @@ -0,0 +1,20 @@ +package de.tobias.playpad.viewcontroller.cell.errordialog; + +import de.tobias.playpad.pad.PadException; +import javafx.scene.control.Control; +import javafx.scene.control.TableCell; +import javafx.scene.text.Text; + + +public class ErrorCell extends TableCell<PadException, String> { + + + public ErrorCell() { + Text text = new Text(); + text.getStyleClass().add("label"); + setGraphic(text); + setPrefHeight(Control.USE_COMPUTED_SIZE); + text.wrappingWidthProperty().bind(widthProperty()); + text.textProperty().bind(itemProperty()); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/FixCell.java b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/FixCell.java new file mode 100644 index 0000000000000000000000000000000000000000..4dd2458946d4ff8295964d8f282105bccd916efe --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/cell/errordialog/FixCell.java @@ -0,0 +1,92 @@ +package de.tobias.playpad.viewcontroller.cell.errordialog; + +import java.nio.file.Files; +import java.nio.file.Path; + +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadException; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.view.ExceptionButton; +import de.tobias.utils.util.FileUtils; +import javafx.scene.control.Button; +import javafx.scene.control.TableCell; +import javafx.stage.Stage; + +public class FixCell extends TableCell<PadException, PadException> { + + private Stage stage; + + public FixCell(Stage stage) { + this.stage = stage; + } + + @Override + protected void updateItem(PadException item, boolean empty) { + super.updateItem(item, empty); + if (!empty) { + switch (item.getType()) { + case FILE_NOT_FOUND: + ExceptionButton<Path> notExistsExButton = ExceptionButton.FILE_NOT_FOUND_EXCEPTION; + Button notExistsButton = notExistsExButton.getButton(); + notExistsButton.setOnAction(a -> + { + Path path = notExistsExButton.getHandler().handle(item.getPad(), stage); + if (path != null) { + + Pad pad = item.getPad(); + PadContent content = item.getPad().getContent(); + try { + PadContentConnect padContentConnect = PadContentRegistry.getPadContentConnect(content.getType()); + + if (Files.exists(path) && PadContentConnect.isFileSupported(path, padContentConnect)) { + content.handlePath(path); + pad.setName(FileUtils.getFilenameWithoutExtention(path.getFileName())); + pad.removeException(item); + } + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + }); + setGraphic(notExistsButton); + break; + + case FILE_FORMAT_NOT_SUPPORTED: + case CONVERT_NOT_SUPPORTED: + ExceptionButton<Path> supportExButton = ExceptionButton.FILE_NOT_FOUND_EXCEPTION; + Button supportButton = supportExButton.getButton(); + supportButton.setOnAction(a -> + { + Path path = supportExButton.getHandler().handle(item.getPad(), stage); + if (path != null) { + + Pad pad = item.getPad(); + PadContent content = item.getPad().getContent(); + try { + PadContentConnect padContentConnect = PadContentRegistry.getPadContentConnect(content.getType()); + + if (Files.exists(path) && PadContentConnect.isFileSupported(path, padContentConnect)) { + content.handlePath(path); + pad.setName(FileUtils.getFilenameWithoutExtention(path.getFileName())); + pad.removeException(item); + } + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + }); + setGraphic(supportButton); + break; + + default: + break; + } + } else { + setGraphic(null); + } + setText(""); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ChangelogDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ChangelogDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..742c07fd81d1ea48256bce922099c0a4502ece2a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ChangelogDialog.java @@ -0,0 +1,66 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import de.tobias.playpad.AppUserInfoStrings; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.concurrent.Worker.State; +import javafx.fxml.FXML; +import javafx.scene.web.WebView; +import javafx.stage.Stage; +import netscape.javascript.JSObject; + +public class ChangelogDialog extends ViewController { + + @FXML private WebView contentView; + private JSBridge bridge; + + public ChangelogDialog() { + super("changelogDialog", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + + if (ApplicationUtils.getApplication().isUpdated()) { + bridge = new JSBridge(); + + contentView.getEngine().getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> + { + if (newState == State.SUCCEEDED) { + JSObject window = (JSObject) contentView.getEngine().executeScript("window"); + window.setMember("app", bridge); + getStage().show(); + } + }); + + String url = ApplicationUtils.getApplication().getInfo().getUserInfo().getString(AppUserInfoStrings.CHANGELOG_URL) + "&version=" + + ApplicationUtils.getApplication().getOldVersionNumber(); + contentView.getEngine().load(url); + getStage().show(); + } + } + + @Override + public void init() { + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setWidth(500); + stage.setMinWidth(500); + stage.setMaxWidth(500); + + stage.setMinHeight(700); + stage.setTitle(Localization.getString(Strings.UI_Window_Changelog_Title)); + stage.setAlwaysOnTop(true); + } + + public class JSBridge { + + public void close() { + getStage().close(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DragAndDropDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DragAndDropDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..76304d7e8af88fdd4e580be3d389bb8530333958 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DragAndDropDialog.java @@ -0,0 +1,48 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.utils.util.Localization; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class DragAndDropDialog extends Dialog<Void> { + + private CheckBox displayOnceCheckBox; + + public DragAndDropDialog(Window owner) { + setHeaderText(Localization.getString(Strings.UI_Dialog_DragAndDrop_Header)); + setGraphic(new ImageView("org/controlsfx/dialog/dialog-information.png")); + + Label textLabel = new Label(Localization.getString(Strings.UI_Dialog_DragAndDrop_Content)); + textLabel.setWrapText(true); + textLabel.setMaxWidth(450); + ImageView view = new ImageView("de/tobias/playpad/assets/files/dialogDnD.png"); + + displayOnceCheckBox = new CheckBox(Localization.getString(Strings.UI_Standard_DoNotShow)); + + VBox box = new VBox(textLabel, view, displayOnceCheckBox); + box.setSpacing(10); + getDialogPane().setContent(box); + + ButtonType buttonTypeOk = new ButtonType(Localization.getString(Strings.UI_Dialog_DragAndDrop_Button), ButtonData.OK_DONE); + getDialogPane().getButtonTypes().add(buttonTypeOk); + + initOwner(owner); + initModality(Modality.WINDOW_MODAL); + Stage dialogStage = (Stage) getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialogStage.getIcons()::add); + } + + public boolean isPermanentSelected() { + return displayOnceCheckBox.isSelected(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProfileDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProfileDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..8556d72177365c43b1a3e563c2e2f976ffd8e2ee --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProfileDialog.java @@ -0,0 +1,63 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.util.Optional; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; +import javafx.stage.Modality; +import javafx.stage.Stage; + +public class DuplicateProfileDialog extends TextInputDialog { + + private ProfileReference newRef; + + public DuplicateProfileDialog(ViewController controller, ProfileReference cloneableProfile) { + initOwner(controller.getStage()); + initModality(Modality.WINDOW_MODAL); + Stage dialog = (Stage) getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + + Button button = (Button) getDialogPane().lookupButton(ButtonType.OK); + getEditor().textProperty().addListener((a, b, c) -> + { + if (ProfileReference.getProfiles().contains(c) || !c.matches(Profile.profileNameEx)) { + button.setDisable(true); + } else { + button.setDisable(false); + } + }); + + setContentText(Localization.getString(Strings.UI_Dialog_NewProfile_Content)); + showAndWait().filter(name -> !name.isEmpty()).ifPresent(name -> + { + try { + if (ProfileReference.getProfiles().contains(name)) { + controller.showErrorMessage(Localization.getString(Strings.Error_Standard_NameInUse, name)); + return; + } + + newRef = new ProfileReference(name); + ProfileReference.duplicate(cloneableProfile, newRef); + + } catch (Exception e) { + e.printStackTrace(); + controller.showErrorMessage(Localization.getString(Strings.Error_Profile_Save, e.getMessage())); + } + }); + } + + public Optional<ProfileReference> getName() { + if (newRef != null) { + return Optional.of(newRef); + } else { + return Optional.empty(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProjectDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProjectDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..d4bbfd864346d13b9efde1988e29e3e8604edf6f --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/DuplicateProjectDialog.java @@ -0,0 +1,74 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.util.Optional; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; +import javafx.stage.Modality; +import javafx.stage.Stage; + +public class DuplicateProjectDialog extends TextInputDialog { + + private ProjectReference ref; + + public DuplicateProjectDialog(ViewController controller, ProjectReference cloneableProject) { + initOwner(controller.getStage()); + initModality(Modality.WINDOW_MODAL); + Stage dialog = (Stage) getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + + setResultConverter(button -> + { + String param = getEditor().getText(); + if (!param.endsWith(PlayPadMain.projectType[0].substring(1))) { + param += PlayPadMain.projectType[0].substring(1); + } + + ButtonData data = button == null ? null : button.getButtonData(); + return data == ButtonData.OK_DONE ? param : null; + }); + + Button button = (Button) getDialogPane().lookupButton(ButtonType.OK); + getEditor().textProperty().addListener((a, b, c) -> + { + if (ProjectReference.getProjects().contains(c) || !c.matches(Project.projectNameEx)) { + button.setDisable(true); + } else { + button.setDisable(false); + } + }); + + setContentText(Localization.getString(Strings.UI_Dialog_NewProject_Content)); + showAndWait().filter(name -> !name.isEmpty()).ifPresent(name -> + { + try { + if (ProfileReference.getProfiles().contains(name)) { + controller.showErrorMessage(Localization.getString(Strings.Error_Standard_NameInUse, name)); + return; + } + + ref = ProjectReference.duplicate(cloneableProject, name); + } catch (Exception e) { + e.printStackTrace(); + controller.showErrorMessage(Localization.getString(Strings.Error_Project_Save, name, e.getMessage())); + } + }); + } + + public Optional<ProjectReference> getName() { + if (ref != null) { + return Optional.of(ref); + } else { + return Optional.empty(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ErrorSummaryDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ErrorSummaryDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..d8f79dd00d3b4a2034c3973a59195b8f88e5ea2a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ErrorSummaryDialog.java @@ -0,0 +1,134 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.PadException; +import de.tobias.playpad.pad.PadException.PadExceptionType; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.errordialog.ErrorCell; +import de.tobias.playpad.viewcontroller.cell.errordialog.FixCell; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.ListChangeListener; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class ErrorSummaryDialog extends ViewController { + + private static ErrorSummaryDialog instance; + + @FXML private TableView<PadException> errorTable; + + @FXML private TableColumn<PadException, String> padColumn; + @FXML private TableColumn<PadException, String> errorColumn; + @FXML private TableColumn<PadException, PadException> fixColumn; + + @FXML private Button closeButton; + + public ErrorSummaryDialog(Window owner) { + super("errorSummaryDialog", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + instance = this; + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + } + + @Override + public void init() { + errorTable.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_ErrorSummary))); + // Disable das etwas ausgewählt werden kann + errorTable.setSelectionModel(null); + + padColumn.setCellValueFactory(param -> + { + StringProperty value = new SimpleStringProperty(param.getValue().getPad().toString()); + return value; + }); + + errorColumn.setCellFactory(param -> new ErrorCell()); + errorColumn.setCellValueFactory(param -> + + { + PadException padException = param.getValue(); + String string = ""; + try { + if (padException.getType() == PadExceptionType.UNKOWN_CONTENT_TYPE) + string = Localization.getString(Strings.Error_Pad_BaseName + padException.getType().name(), + padException.getPad().getIndexReadable()); + else + string = Localization.getString(Strings.Error_Pad_BaseName + padException.getType().name(), padException.getPath()); + } catch (Exception e) { + e.printStackTrace(); + } + StringProperty value = new SimpleStringProperty(string); + return value; + }); + + fixColumn.setCellFactory(param -> new FixCell(getStage())); + fixColumn.setCellValueFactory(param -> + + { + ObjectProperty<PadException> type = new SimpleObjectProperty<>(param.getValue()); + return type; + }); + + // Close CMD+W + getStage().getScene().getAccelerators().put(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN), + () -> Platform.runLater(() -> getStage().close())); + } + + public void setProject(Project project) { + errorTable.setItems(project.getExceptions()); + errorTable.getItems().addListener(new ListChangeListener<PadException>() { + + @Override + public void onChanged(javafx.collections.ListChangeListener.Change<? extends PadException> c) { + if (!errorTable.getItems().isEmpty()) { + getStage().show(); + } else { + getStage().close(); + } + } + }); + } + + @Override + public void initStage(Stage stage) { + stage.setMinWidth(900); + stage.setMinHeight(300); + + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_ErrorSummary_Title)); + stage.setWidth(900); + stage.setHeight(300); + + if (Profile.currentProfile() != null) + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void closeButtonHandler(ActionEvent event) { + getStage().close(); + } + + public static ErrorSummaryDialog getInstance() { + return instance; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ExportDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ExportDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..eebd0d8ba87e3fe640b0ad3beec4eb82b9065093 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ExportDialog.java @@ -0,0 +1,101 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.File; +import java.io.IOException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.ProjectExporter; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.ui.scene.BusyView; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class ExportDialog extends ViewController { + + @FXML private CheckBox profileCheckBox; + @FXML private CheckBox mediaCheckBox; + + @FXML private Button cancelButton; + @FXML private Button saveButton; + + private BusyView busyView; + + private ProjectReference projectRef; + private NotificationHandler notificationHandler; + + public ExportDialog(ProjectReference projectRef, Window owner, NotificationHandler notificationHandler) { + super("exportDialog", "de/tobias/playpad/assets/dialog/project/", null, PlayPadMain.getUiResourceBundle()); + this.projectRef = projectRef; + this.notificationHandler = notificationHandler; + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + busyView = new BusyView(this); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_ProjectExport_Title)); + stage.setWidth(320); + stage.setHeight(180); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void saveButtonHandler(ActionEvent event) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters() + .add(new ExtensionFilter(Localization.getString(Strings.File_Filter_ZIP), PlayPadMain.projectCompressedType)); + File file = chooser.showSaveDialog(getStage()); + if (file != null) { + cancelButton.setDisable(true); + busyView.showProgress(true); + + Worker.runLater(() -> + { + try { + ProjectExporter.exportProject(projectRef, file.toPath(), profileCheckBox.isSelected(), mediaCheckBox.isSelected()); + + Platform.runLater(() -> + { + busyView.showProgress(false); + getStage().close(); + notificationHandler.notify(Localization.getString(Strings.Standard_File_Save), + PlayPadMain.notificationDisplayTimeMillis); + }); + } catch (IOException e) { + e.printStackTrace(); + Platform.runLater(() -> + { + busyView.showProgress(false); + showErrorMessage(Localization.getString(Strings.Error_Project_Export, projectRef.getName(), e.getMessage()), + PlayPadMain.stageIcon); + }); + } + }); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ImportDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ImportDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..a1e8fbf6ef6d4655147014a4d0a77693a430999e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ImportDialog.java @@ -0,0 +1,131 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.Importable; +import de.tobias.playpad.project.ProfileChooseable; +import de.tobias.playpad.settings.Profile; +import de.tobias.utils.util.Localization; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; +import javafx.stage.DirectoryChooser; +import javafx.stage.Modality; +import javafx.stage.Stage; + +public class ImportDialog implements Importable, ProfileChooseable { + + private static ImportDialog instance; + private static Stage owner; + + static { + instance = new ImportDialog(); + } + + public static ImportDialog getInstance(Stage stage) { + ImportDialog.owner = stage; + return instance; + } + + private Stage getStage() { + return owner; + } + + @Override + public String replaceProfile(String name) { + Alert replaceAlert = new Alert(AlertType.CONFIRMATION); + replaceAlert.initOwner(getStage()); + replaceAlert.initModality(Modality.WINDOW_MODAL); + replaceAlert.setContentText(Localization.getString(Strings.UI_Dialog_Import_ReplaceProfile_Content, name)); + + ButtonType skipButton = new ButtonType(Localization.getString(Strings.UI_Dialog_Import_ReplaceProfile_Skip)); + ButtonType renameButton = new ButtonType(Localization.getString(Strings.UI_Dialog_Import_ReplaceProfile_Rename)); + replaceAlert.getButtonTypes().setAll(skipButton, renameButton); + + Stage replaceStage = (Stage) replaceAlert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(replaceStage.getIcons()::add); + + Optional<ButtonType> resultButton = replaceAlert.showAndWait(); + if (resultButton.isPresent()) { + if (resultButton.get() == renameButton) { + TextInputDialog alert = new TextInputDialog(name); + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(Localization.getString(Strings.UI_Dialog_Import_ReplaceProfile_ReplaceContent, name)); + + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + if (alert.showAndWait().filter(item -> item != null).isPresent()) { + return alert.getResult(); + } + } else { + return null; + } + } + return null; + } + + @Override + public String replaceProject(String name) { + TextInputDialog alert = new TextInputDialog(name.replace(PlayPadMain.projectType[0].substring(1), "")); + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(Localization.getString(Strings.UI_Dialog_Import_ReplaceProject_ReplaceContent, name)); + + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + if (alert.showAndWait().filter(item -> item != null).isPresent()) { + return alert.getResult(); + } + + return null; + } + + @Override + public Path mediaFolder() { + Alert copyMediaAlert = new Alert(AlertType.CONFIRMATION); + copyMediaAlert.initOwner(getStage()); + copyMediaAlert.initModality(Modality.WINDOW_MODAL); + copyMediaAlert.setContentText(Localization.getString(Strings.UI_Dialog_Import_ReplaceMedia_Content)); + + ButtonType copyButton = new ButtonType(Localization.getString(Strings.UI_Dialog_Import_ReplaceMedia_Copy)); + ButtonType skipButton = new ButtonType(Localization.getString(Strings.UI_Dialog_Import_ReplaceMedia_Skip)); + + copyMediaAlert.getButtonTypes().setAll(copyButton, skipButton); + + Stage replaceStage = (Stage) copyMediaAlert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(replaceStage.getIcons()::add); + + Optional<ButtonType> resultButton = copyMediaAlert.showAndWait(); + if (resultButton.isPresent()) { + if (resultButton.get() == copyButton) { + DirectoryChooser chooser = new DirectoryChooser(); + File file = chooser.showDialog(owner); + if (file != null) { + return file.toPath(); + } + } + } + return null; + } + + @Override + public Profile getUnkownProfile() { + ProfileChooseDialog dialog = new ProfileChooseDialog(getStage()); + + dialog.getStage().showAndWait(); + Profile profile = dialog.getProfile(); + if (profile != null) { + return profile; + } + return null; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/MappingListViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/MappingListViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..e82fd677771bb7798c9881b7895e710c859abb9c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/MappingListViewController.java @@ -0,0 +1,225 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.MappingList; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.DisplayableCell; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class MappingListViewController extends ViewController { + + @FXML private ComboBox<Mapping> presetsListView; + + @FXML private TextField nameTextField; + + @FXML private Button addButton; + @FXML private Button removeButton; + @FXML private Button importButton; + @FXML private Button exportButton; + @FXML private Button duplicateButton; + + @FXML private Button finishButton; + + private MappingList mappingList; + + public MappingListViewController(MappingList mappingList, Window window) { + super("mappingView", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + this.mappingList = mappingList; + + getStage().initOwner(window); + + presetsListView.getItems().addAll(mappingList); + presetsListView.getSelectionModel().selectFirst(); + + if (mappingList.size() == 1) { + removeButton.setDisable(true); + } + } + + @Override + public void init() { + presetsListView.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_Preset))); + + // Ausgewählte in der Liste rechts zeigen und Button disablen + presetsListView.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + showPreset(c); + if (c == null) { + exportButton.setDisable(true); + if (mappingList.size() <= 1) + removeButton.setDisable(true); + } else { + removeButton.setDisable(false); + exportButton.setDisable(false); + } + }); + + // Name des Presets aktualisieren + nameTextField.textProperty().addListener((a, b, c) -> + { + Mapping item = getSelectedMidiPreset(); + if (item != null) { + item.setName(c); + } + }); + + presetsListView.setCellFactory(item -> new DisplayableCell<>()); + presetsListView.setButtonCell(new DisplayableCell<>()); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + stage.initModality(Modality.WINDOW_MODAL); + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(500); + stage.setMinHeight(200); + stage.setTitle(Localization.getString(Strings.UI_Dialog_Preset_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + private void showPreset(Mapping midiPreset) { + if (midiPreset != null) { + nameTextField.setText(midiPreset.getName()); + } else { + nameTextField.setText(null); + } + } + + @FXML + private void addButtonHandler(ActionEvent event) { + Mapping preset = new Mapping(true, Profile.currentProfile()); + + mappingList.add(preset); + presetsListView.getItems().add(preset); + presetsListView.getSelectionModel().select(preset); + + if (mappingList.size() > 1) { + removeButton.setDisable(false); + } + } + + @FXML + private void duplicateButtonHandler() { + Mapping preset = getSelectedMidiPreset(); + try { + Mapping clonedMapping = preset.clone(); + clonedMapping.setName(Localization.getString(Strings.Standard_Copy, clonedMapping.getName())); + + // Model + mappingList.add(clonedMapping); + // UI + presetsListView.getItems().add(preset); + presetsListView.getSelectionModel().select(clonedMapping); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + } + + @FXML + private void removeButtonHandler(ActionEvent event) { + int preset = presetsListView.getSelectionModel().getSelectedIndex(); + + mappingList.remove(preset); + presetsListView.getItems().remove(preset); + + if (mappingList.size() == 1) { + removeButton.setDisable(true); + } + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void importButtonHandler(ActionEvent event) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters().add(new ExtensionFilter(Localization.getString(Strings.File_Filter_Preset), PlayPadMain.midiPresetType)); + File file = chooser.showOpenDialog(getStage()); + if (file != null) { + Path path = file.toPath(); + + Worker.runLater(() -> + { + try { + Mapping preset = MappingList.importMappingPreset(path, Profile.currentProfile()); + mappingList.add(preset); + Platform.runLater(() -> + { + presetsListView.getItems().add(preset); + presetsListView.getSelectionModel().select(preset); + + if (mappingList.size() == 1) { + removeButton.setDisable(true); + } else { + removeButton.setDisable(false); + } + + showInfoMessage(Localization.getString(Strings.Standard_File_Save)); + }); + + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Preset_Import, e.getLocalizedMessage())); + } + }); + } + } + + @FXML + private void exportButtonHandler(ActionEvent event) { + Mapping preset = getSelectedMidiPreset(); + if (preset != null) { + FileChooser chooser = new FileChooser(); + + ExtensionFilter filter = new ExtensionFilter(Localization.getString(Strings.File_Filter_Preset), PlayPadMain.midiPresetType); + chooser.getExtensionFilters().add(filter); + + File file = chooser.showSaveDialog(getStage()); + if (file != null) { + Path path = file.toPath(); + + Worker.runLater(() -> + { + try { + MappingList.exportMidiPreset(path, preset); + showInfoMessage(Localization.getString(Strings.Standard_File_Save)); + } catch (IOException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Preset_Export, e.getLocalizedMessage())); + } + }); + } + } + } + + private Mapping getSelectedMidiPreset() { + return presetsListView.getSelectionModel().getSelectedItem(); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProfileDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProfileDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..294c7f99b43d034d9eeba22752ee2f7200d82654 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProfileDialog.java @@ -0,0 +1,154 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import javax.sound.midi.MidiDevice.Info; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Accordion; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class NewProfileDialog extends ViewController { + + @FXML private TextField nameTextField; + @FXML private CheckBox activeCheckBox; + @FXML private ComboBox<String> midiDeviceComboBox; + + @FXML private Button finishButton; + @FXML private Button cancelButton; + + @FXML private VBox accordionParent; + @FXML private Accordion accordion; + + private Profile profile; + + public NewProfileDialog(Window owner) { + super("newProfileDialog", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + midiDeviceComboBox.setDisable(!activeCheckBox.isSelected()); + + // In Worker, da Midi.getMidiDevices etwas dauert und FX-Thread sonst blockiert + Worker.runLater(() -> + { + Info[] data = Midi.getMidiDevices(); + + // Gerät anzeigen - Doppelte weg + Platform.runLater(() -> + { + for (Info item : data) { + if (!midiDeviceComboBox.getItems().contains(item.getName())) { + midiDeviceComboBox.getItems().add(item.getName()); + } + } + }); + }); + getStage().sizeToScene(); + } + + private boolean expand = false; + + @Override + public void init() { + accordion.heightProperty().addListener((obs, oldHeight, newHeight) -> + { + if (newHeight.doubleValue() > oldHeight.doubleValue()) { + if (accordionParent.getHeight() <= newHeight.doubleValue()) { + getStage().setHeight(getStage().getHeight() + newHeight.doubleValue()); + expand = true; + } + } else { + if (expand) + getStage().setHeight(getStage().getHeight() - oldHeight.doubleValue()); + expand = false; + } + }); + + nameTextField.textProperty().addListener((a, b, c) -> + { + if (c.isEmpty()) { + finishButton.setDisable(true); + } else { + if (ProfileReference.getProfiles().contains(c) || !c.matches(Profile.profileNameEx)) { + finishButton.setDisable(true); + return; + } + finishButton.setDisable(false); + } + }); + finishButton.setDisable(true); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_NewProile_Title)); + stage.setWidth(400); + stage.setHeight(200); + + stage.setMinWidth(500); + stage.setMinHeight(200); + + stage.setMaxWidth(500); + + if (Profile.currentProfile() != null) { + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + } + + @FXML + private void activeCheckBoxHandler(ActionEvent actionEvent) { + midiDeviceComboBox.setDisable(!activeCheckBox.isSelected()); + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + String name = nameTextField.getText(); + try { + if (ProfileReference.getProfiles().contains(name) || !name.matches(Profile.profileNameEx)) { + showErrorMessage(Localization.getString(Strings.Error_Standard_NameInUse, name)); + return; + } + + profile = ProfileReference.newProfile(name); + + profile.getProfileSettings().setMidiActive(activeCheckBox.isSelected()); + profile.getProfileSettings().setMidiDeviceName(midiDeviceComboBox.getSelectionModel().getSelectedItem()); + + profile.save(); + getStage().close(); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Profile_Create, e.getMessage())); + } + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + getStage().close(); + } + + public Profile getProfile() { + return profile; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProjectDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProjectDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..973a5a43db38b233c796e259acca9db58d28e58c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/NewProjectDialog.java @@ -0,0 +1,135 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.IOException; +import java.util.UUID; + +import org.dom4j.DocumentException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileNotFoundException; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextField; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +/** + * Create an new project and adds it to the project reference list + * + * @author tobias + * + */ +public class NewProjectDialog extends ViewController { + + @FXML private TextField nameTextField; + @FXML private ComboBox<ProfileReference> profileComboBox; + @FXML private Button newProfileButton; + + @FXML private Button finishButton; + @FXML private Button cancelButton; + + private Project project; + + public NewProjectDialog(Window owner) { + super("newProjectDialog", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + profileComboBox.getItems().addAll(ProfileReference.getProfiles()); + profileComboBox.getSelectionModel().selectFirst(); + } + + @Override + public void init() { + nameTextField.textProperty().addListener((a, b, c) -> + { + if (c.isEmpty()) { + finishButton.setDisable(true); + } else { + if (ProjectReference.getProjects().contains(c) || !c.matches(Project.projectNameEx)) { + finishButton.setDisable(true); + return; + } + finishButton.setDisable(false); + } + }); + finishButton.setDisable(true); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_NewProject_Title)); + stage.setWidth(560); + stage.setHeight(250); + + stage.setMinWidth(560); + stage.setMinHeight(250); + + stage.setMaxWidth(560); + + if (Profile.currentProfile() != null) { + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + } + + @FXML + private void finishButtonHandler(ActionEvent evenet) { + try { + Profile profile = Profile.load(profileComboBox.getSelectionModel().getSelectedItem()); + + String name = nameTextField.getText(); + UUID uuid = UUID.randomUUID(); + + ProjectReference projectReference = new ProjectReference(uuid, name, profile.getRef()); + + project = new Project(projectReference); + project.save(); + + ProjectReference.addProject(projectReference); + + getStage().close(); + } catch (IOException | DocumentException | ProfileNotFoundException e) { + showErrorMessage(Localization.getString(Strings.Error_Project_Create, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void newProfileButtonHandler(ActionEvent event) { + NewProfileDialog dialog = new NewProfileDialog(getStage()); + dialog.getStage().showAndWait(); + + Profile profile = dialog.getProfile(); + + // In GUI hinzufügen (am Ende) und auswählen + if (profile != null) { + profileComboBox.getItems().add(profile.getRef()); + profileComboBox.getSelectionModel().selectLast(); + } + } + + public Project getProject() { + return project; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileChooseDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileChooseDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..16362ff2cae9c234455fbbab6f86d343eafeafaa --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileChooseDialog.java @@ -0,0 +1,93 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.IOException; + +import org.dom4j.DocumentException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileNotFoundException; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class ProfileChooseDialog extends ViewController { + + @FXML private ComboBox<ProfileReference> profileComboBox; + @FXML private Button newProfileButton; + + @FXML private Button finishButton; + @FXML private Button cancelButton; + + private Profile profile; + + public ProfileChooseDialog(Window owner) { + super("profileChooseDialog", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + profileComboBox.getItems().addAll(ProfileReference.getProfiles()); + profileComboBox.getSelectionModel().selectFirst(); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_ChooseProfile_Title)); + stage.setWidth(560); + stage.setHeight(180); + stage.setMinWidth(560); + stage.setMinHeight(180); + stage.setMaxWidth(560); + + if (Profile.currentProfile() != null) { + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + } + + @FXML + private void finishButtonHandler(ActionEvent evenet) { + try { + profile = Profile.load(profileComboBox.getSelectionModel().getSelectedItem()); + + getStage().close(); + } catch (IOException | DocumentException | ProfileNotFoundException e) { + showErrorMessage(Localization.getString(Strings.Error_Profile_Save, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void newProfileButtonHandler(ActionEvent event) { + NewProfileDialog dialog = new NewProfileDialog(getStage()); + dialog.getStage().showAndWait(); + + Profile profile = dialog.getProfile(); + + // In GUI hinzufügen (am Ende) und auswählen + if (profile != null) { + profileComboBox.getItems().add(profile.getRef()); + profileComboBox.getSelectionModel().selectLast(); + } + } + + public Profile getProfile() { + return profile; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..afd7641c48aaffa3b3709727e00337758fe041ce --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProfileViewController.java @@ -0,0 +1,200 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.IOException; + +import org.dom4j.DocumentException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileNotFoundException; +import de.tobias.playpad.settings.ProfileReference; +import de.tobias.playpad.viewcontroller.cell.DisplayableCell; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class ProfileViewController extends ViewController implements ChangeListener<ProfileReference> { + + @FXML private ListView<ProfileReference> profileList; + @FXML private TextField nameTextField; + + @FXML private Button newButton; + @FXML private Button duplicateButton; + @FXML private Button deleteButton; + @FXML private Button renameButton; + + @FXML private Button chooseButton; + + private Project project; + + public ProfileViewController(Window owner, Project project) { + super("profileSettingsView", "de/tobias/playpad/assets/dialog/", null, PlayPadMain.getUiResourceBundle()); + profileList.getSelectionModel().select(Profile.currentProfile().getRef()); + this.project = project; + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + + if (ProfileReference.getProfiles().size() == 1 + || profileList.getSelectionModel().getSelectedItem().equals(Profile.currentProfile().getRef())) { + deleteButton.setDisable(true); + } + } + + @Override + public void init() { + profileList.getItems().setAll(ProfileReference.getProfiles()); + profileList.setCellFactory(list -> new DisplayableCell<>()); + + nameTextField.textProperty().addListener((a, b, c) -> + { + if (c != null) { + try { + if ((ProfileReference.getProfiles().contains(c) && !profileList.getSelectionModel().getSelectedItem().equals(c)) + && !c.equals(profileList.getSelectionModel().getSelectedItem().getName())) { + nameTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } else { + nameTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + } + } catch (Exception e) { + nameTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + } else { + nameTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + }); + + profileList.getSelectionModel().selectedItemProperty().addListener(this); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setTitle(Localization.getString(Strings.UI_Dialog_Profile_Title)); + stage.setMinWidth(375); + stage.setMinHeight(500); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void chooseButtonHandler(ActionEvent event) { + ProfileReference ref = profileList.getSelectionModel().getSelectedItem(); + project.getRef().setProfileReference(ref); + + try { + Profile.load(ref); + } catch (ProfileNotFoundException | DocumentException | IOException e) { + e.printStackTrace(); + } + getStage().close(); + } + + @FXML + private void newButtonHandler(ActionEvent event) { + NewProfileDialog dialog = new NewProfileDialog(getStage()); + dialog.getStage().showAndWait(); + + Profile profile = dialog.getProfile(); + + if (profile != null) { + ProfileReference ref = profile.getRef(); + profileList.getItems().add(ref); + selectProfile(ref); + } + } + + @FXML + private void duplicateButtonHandler(ActionEvent event) { + if (profileList.getSelectionModel().getSelectedItem() != null) { + DuplicateProfileDialog dialog = new DuplicateProfileDialog(this, profileList.getSelectionModel().getSelectedItem()); + + dialog.getName().ifPresent(newRef -> + { + profileList.getItems().add(newRef); + selectProfile(newRef); + }); + } + } + + @FXML + private void deleteButtonHandler() { + Alert alert = new Alert(AlertType.CONFIRMATION); + + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + + ProfileReference ref = profileList.getSelectionModel().getSelectedItem(); + + alert.setContentText(Localization.getString(Strings.UI_Dialog_Profile_Delete_Content, ref)); + alert.showAndWait().filter(button -> button == ButtonType.OK).ifPresent(button -> + { + try { + ProfileReference.removeProfile(ref); + profileList.getItems().remove(ref); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Profile_Delete, e.getMessage())); + } + }); + } + + @FXML + private void renameButtonHandler(ActionEvent event) { + ProfileReference ref = profileList.getSelectionModel().getSelectedItem(); + try { + String newProfileName = nameTextField.getText(); + if (ProfileReference.getProfiles().contains(newProfileName) || !newProfileName.matches(Profile.profileNameEx)) { + showErrorMessage(Localization.getString(Strings.Error_Standard_NameInUse, newProfileName)); + return; + } + ref.setName(newProfileName); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Standard_Gen, ref.getName(), e.getMessage())); + } + } + + private void selectProfile(ProfileReference ref) { + profileList.getSelectionModel().select(ref); + } + + @Override + public void changed(ObservableValue<? extends ProfileReference> observable, ProfileReference oldValue, ProfileReference newValue) { + if (newValue != null) { + nameTextField.setText(newValue.getName()); + } else { + nameTextField.clear(); + } + renameButton.setDisable(newValue == null); + chooseButton.setDisable(newValue == null); + duplicateButton.setDisable(newValue == null); + + if (ProfileReference.getProfiles().size() == 1 || profileList.getSelectionModel().getSelectedItem() == null + || profileList.getSelectionModel().getSelectedItem().equals(Profile.currentProfile().getRef())) { + deleteButton.setDisable(true); + } else { + deleteButton.setDisable(false); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProjectManagerDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProjectManagerDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..33bf43df585597d188dc49079d8c63e3e504a8bc --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/ProjectManagerDialog.java @@ -0,0 +1,326 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import org.dom4j.DocumentException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectImporter; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.cell.ProjectCell; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.ui.scene.NotificationPane; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.NumberUtils; +import de.tobias.utils.util.TimeUtils; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.input.MouseButton; +import javafx.scene.layout.AnchorPane; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class ProjectManagerDialog extends ViewController implements NotificationHandler { + + @FXML private ListView<ProjectReference> projectList; + + @FXML private Button openButton; + @FXML private Button cancelButton; + + @FXML private TextField nameTextField; + @FXML private Button renameButton; + + @FXML private Button newButton; + @FXML private Button duplicateButton; + @FXML private Button deleteButton; + + @FXML private Button importButton; + @FXML private Button exportButton; + + @FXML private Label dateLabel; + @FXML private Label sizeLabel; + + private Project currentProject; + + private NotificationPane notificationPane; + @FXML private AnchorPane rootNode; + + private boolean cancel = false; + + public ProjectManagerDialog(Window owner, Project currentProject) { + super("openDialog", "de/tobias/playpad/assets/dialog/project/", null, PlayPadMain.getUiResourceBundle()); + this.currentProject = currentProject; + + projectList.getItems().setAll(ProjectReference.getProjectsSorted()); + + getStage().initOwner(owner); + getStage().initModality(Modality.WINDOW_MODAL); + } + + @Override + public void init() { + // Notification Handler + notificationPane = new NotificationPane(rootNode); + notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK); + + setAnchor(notificationPane, 0, 0, 0, 0); + ((AnchorPane) getParent()).getChildren().add(notificationPane); + + projectList.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_Project))); + projectList.setCellFactory(list -> new ProjectCell()); + + projectList.setOnMouseClicked(mouseEvent -> + { + if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) { + if (mouseEvent.getClickCount() == 2) { + if (!projectList.getSelectionModel().isEmpty()) { + getStage().close(); + } + } + } + }); + projectList.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + if (c != null) { + ProjectReference ref = getSelectedProject(); + + openButton.setDisable(false); + duplicateButton.setDisable(false); + exportButton.setDisable(false); + renameButton.setDisable(false); + + nameTextField.setText(c.toString()); + try { + sizeLabel.setText(NumberUtils.numberToString(ref.getSize())); + dateLabel.setText(TimeUtils.getDfmLong().format(ref.getLastMofied())); + } catch (Exception e) { + sizeLabel.setText("-"); + dateLabel.setText("-"); + e.printStackTrace(); + } + + if (currentProject.getRef().equals(c)) { + deleteButton.setDisable(true); + } else { + deleteButton.setDisable(false); + } + } else { + openButton.setDisable(true); + deleteButton.setDisable(true); + duplicateButton.setDisable(true); + exportButton.setDisable(true); + renameButton.setDisable(true); + + nameTextField.setText(null); + sizeLabel.setText("-"); + dateLabel.setText("-"); + } + }); + + openButton.setDisable(true); + deleteButton.setDisable(true); + duplicateButton.setDisable(true); + exportButton.setDisable(true); + renameButton.setDisable(true); + + sizeLabel.setText("-"); + dateLabel.setText("-"); + + addCloseKeyShortcut(() -> getStage().close()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(600); + stage.setMinHeight(400); + stage.setWidth(600); + stage.setHeight(400); + stage.setTitle(Localization.getString(Strings.UI_Dialog_ProjectManager_Title)); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + @FXML + private void deleteButtonHandler(ActionEvent event) { + ProjectReference ref = getSelectedProject(); + + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setContentText(Localization.getString(Strings.UI_Dialog_ProjectManager_Delete_Content, ref)); + + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + + alert.showAndWait().filter(item -> item == ButtonType.OK).ifPresent(item -> + { + try { + ProjectReference.removeDocument(ref); + projectList.getItems().remove(ref); // VIEW + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Project_Delete, e.getLocalizedMessage())); + } + }); + } + + @FXML + private void cancelButtonHandler(ActionEvent event) { + cancel = true; + getStage().close(); + } + + @FXML + private void openButtonHandler(ActionEvent event) { + getStage().close(); + } + + @FXML + private void renameButtonHandler(ActionEvent event) { + ProjectReference projectReference = getSelectedProject(); + String oldName = projectReference.toString(); + + try { + String newProjectName = (String) nameTextField.getTextFormatter().getValue(); // Name + XML + if (ProjectReference.getProjects().contains(newProjectName) || !nameTextField.getText().matches(Project.projectNameEx)) { + showErrorMessage(Localization.getString(Strings.Error_Standard_NameInUse, nameTextField.getText())); + return; + } + + projectReference.setName(newProjectName); + projectList.getItems().setAll(ProjectReference.getProjectsSorted()); + + selectProject(projectReference); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Project_Rename, oldName, e.getMessage())); + } + } + + @FXML + private void newButtonHandler(ActionEvent event) { + NewProjectDialog dialog = new NewProjectDialog(getStage()); + dialog.getStage().showAndWait(); + + Project project = dialog.getProject(); + projectList.getItems().add(project.getRef()); + } + + @FXML + private void duplicateButtonHandler(ActionEvent event) { + if (getSelecteItem() != null) { + DuplicateProjectDialog dialog = new DuplicateProjectDialog(this, getSelectedProject()); + + dialog.getName().ifPresent(ref -> + { + projectList.getItems().add(ref); + selectProject(ref); + }); + } + } + + @FXML + private void importButtonHandler(ActionEvent event) { + FileChooser chooser = new FileChooser(); + chooser.getExtensionFilters() + .add(new ExtensionFilter(Localization.getString(Strings.File_Filter_ZIP), PlayPadMain.projectCompressedType)); + File file = chooser.showOpenDialog(getStage()); + if (file != null) { + Path zipFile = file.toPath(); + try { + ProjectReference ref = ProjectImporter.importProject(zipFile, ImportDialog.getInstance(getStage()), + ImportDialog.getInstance(getStage())); + projectList.getItems().add(ref); + selectProject(ref); + } catch (IOException | DocumentException e) { + showErrorMessage(Localization.getString(Strings.Error_Project_Open, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + } + + @FXML + private void exportButtonHandler(ActionEvent event) { + ExportDialog dialog = new ExportDialog(getSelectedProject(), getStage(), this); + dialog.getStage().show(); + } + + public Optional<ProjectReference> showAndWait() { + getStage().showAndWait(); + if (!cancel) { + if (getSelecteItem() != null) { + if (currentProject.getRef() != getSelecteItem()) { + return Optional.of(getSelecteItem()); + } + } + } + return Optional.empty(); + } + + private ProjectReference getSelecteItem() { + return projectList.getSelectionModel().getSelectedItem(); + } + + private ProjectReference getSelectedProject() { + return getSelecteItem(); + } + + private void selectProject(ProjectReference ref) { + projectList.getSelectionModel().select(ref); + } + + @Override + public void notify(String text, long duration) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration)); + } + } + + @Override + public void notify(String text, long duration, Runnable finish) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration, finish); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration, finish)); + } + } + + @Override + public void showError(String message) { + if (Platform.isFxApplicationThread()) { + notificationPane.showError(message); + } else { + Platform.runLater(() -> notificationPane.showError(message)); + } + } + + @Override + public void hide() { + if (Platform.isFxApplicationThread()) { + notificationPane.hide(); + } else { + Platform.runLater(() -> notificationPane.hide()); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/UpdaterDialog.java b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/UpdaterDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..6143bc834cdf0810172eef642d3453118feb3e44 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/dialog/UpdaterDialog.java @@ -0,0 +1,30 @@ +package de.tobias.playpad.viewcontroller.dialog; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.utils.util.Localization; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class UpdaterDialog extends Dialog<Void> { + + public UpdaterDialog(Window owner) { + setHeaderText(Localization.getString(Strings.UI_Dialog_DragAndDrop_Header)); + setGraphic(new ImageView("org/controlsfx/dialog/dialog-information.png")); + + Label textLabel = new Label( + "Die Aktualisierung wird vorbereitet. Bitte schließen Sie nicht das Programm. \nDieser Vorgang kann wenige Minuten dauern."); + textLabel.setWrapText(true); + textLabel.setMaxWidth(450); + getDialogPane().setContent(textLabel); + + initOwner(owner); + initModality(Modality.WINDOW_MODAL); + Stage dialogStage = (Stage) getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialogStage.getIcons()::add); + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutCartViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutCartViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..197ff4d30e76056f5c313d784f68b031c080747e --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutCartViewController.java @@ -0,0 +1,95 @@ +package de.tobias.playpad.viewcontroller.layout; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.classic.ClassicCartLayout; +import de.tobias.playpad.viewcontroller.CartLayoutViewController; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ColorPicker; +import javafx.scene.paint.Color; + +public class ClassicLayoutCartViewController extends CartLayoutViewController { + + private ClassicCartLayout layout; + + @FXML private ColorPicker playgroundColorPicker; + @FXML private ColorPicker backgroundColorPicker; + @FXML private ColorPicker warnColorPicker; + @FXML private ColorPicker fadeColorPicker; + + @FXML private ColorPicker infoLabelColorPicker; + @FXML private ColorPicker titleLabelColorPicker; + + @FXML private Button resetButton; + + public ClassicLayoutCartViewController(CartLayout layout) { + super("classicLayoutCart", "de/tobias/playpad/assets/view/option/layout/", PlayPadMain.getUiResourceBundle(), layout); + setLayout((ClassicCartLayout) layout); + } + + @Override + public void init() { + backgroundColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.5) { + backgroundColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.5)); + return; + } + layout.setBackgroundColor(c); + }); + playgroundColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + playgroundColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setPlaybackColor(c); + }); + + warnColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + warnColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setWarnColor(c); + }); + + fadeColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + fadeColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setFadeColor(c); + }); + + infoLabelColorPicker.valueProperty().addListener((a, b, c) -> layout.setInfoLabelColor(c)); + titleLabelColorPicker.valueProperty().addListener((a, b, c) -> layout.setTitleLabelColor(c)); + } + + public void setLayout(ClassicCartLayout defaultLayout) { + this.layout = defaultLayout; + + backgroundColorPicker.setValue(layout.getBackgroundColor()); + playgroundColorPicker.setValue(layout.getPlaybackColor()); + warnColorPicker.setValue(layout.getWarnColor()); + fadeColorPicker.setValue(layout.getFadeColor()); + + infoLabelColorPicker.setValue(layout.getInfoLabelColor()); + titleLabelColorPicker.setValue(layout.getTitleLabelColor()); + } + + @FXML + private void resetButtonHandler(ActionEvent event) { + layout.reset(); + setLayout(layout); + } + + @Override + public void updateData() { + backgroundColorPicker.setValue(layout.getBackgroundColor()); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutGlobalViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutGlobalViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..780435cc39b4974383dd0ecde0539ecd961610ec --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ClassicLayoutGlobalViewController.java @@ -0,0 +1,169 @@ +package de.tobias.playpad.viewcontroller.layout; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.LayoutConnect; +import de.tobias.playpad.layout.classic.ClassicGlobalLayout; +import de.tobias.playpad.layout.classic.Theme; +import de.tobias.playpad.viewcontroller.GlobalLayoutViewController; +import de.tobias.playpad.viewcontroller.cell.ThemeCell; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ColorPicker; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.util.converter.IntegerStringConverter; + +public class ClassicLayoutGlobalViewController extends GlobalLayoutViewController { + + private ClassicGlobalLayout layout; + + @FXML private ComboBox<LayoutConnect> layoutTypeComboBox; + + @FXML private ComboBox<Theme> programLayoutComboBox; + @FXML private ColorPicker accentColorChooser; + @FXML private CheckBox customLayoutCheckBox; + + @FXML private VBox customizeView; + + @FXML private ColorPicker playgroundColorPicker; + @FXML private ColorPicker backgroundColorPicker; + @FXML private ColorPicker warnColorPicker; + @FXML private ColorPicker fadeColorPicker; + + @FXML private ColorPicker infoLabelColorPicker; + @FXML private ComboBox<Integer> infoLabelFontSizeComboBox; + + @FXML private ColorPicker titleLabelColorPicker; + @FXML private ComboBox<Integer> titleLabelFontSizeComboBox; + + @FXML private Button resetButton; + + public ClassicLayoutGlobalViewController(GlobalLayout layout) { + super("classicLayoutGlobal", "de/tobias/playpad/assets/view/option/layout/", PlayPadMain.getUiResourceBundle(), layout); + setLayout((ClassicGlobalLayout) layout); + + ClassicGlobalLayout cl = (ClassicGlobalLayout) layout; + programLayoutComboBox.valueProperty().bindBidirectional(cl.themeProperty()); + accentColorChooser.setValue(cl.getAccentColor()); + customLayoutCheckBox.setSelected(cl.isCustomLayout()); + + customizeView.setDisable(!cl.isCustomLayout()); + } + + @Override + public void init() { + backgroundColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.5) { + backgroundColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.5)); + return; + } + layout.setBackgroundColor(c); + }); + playgroundColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + playgroundColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setPlaybackColor(c); + }); + + warnColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + warnColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setWarnColor(c); + }); + + fadeColorPicker.valueProperty().addListener((a, b, c) -> + { + if (c.getOpacity() > 0.75) { + fadeColorPicker.setValue(new Color(c.getRed(), c.getGreen(), c.getBlue(), 0.75)); + return; + } + layout.setFadeColor(c); + }); + + infoLabelColorPicker.valueProperty().addListener((a, b, c) -> layout.setInfoLabelColor(c)); + infoLabelFontSizeComboBox.getItems().addAll(9, 10, 12, 13, 14, 16, 18, 20, 24, 28); + infoLabelFontSizeComboBox.valueProperty().addListener((a, b, c) -> + { + try { + layout.setInfoLabelFontSize(c); + infoLabelFontSizeComboBox.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + } catch (NumberFormatException e) { + infoLabelFontSizeComboBox.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + }); + infoLabelFontSizeComboBox.setConverter(new IntegerStringConverter()); + + titleLabelColorPicker.valueProperty().addListener((a, b, c) -> layout.setTitleLabelColor(c)); + titleLabelFontSizeComboBox.getItems().addAll(9, 10, 12, 13, 14, 16, 18, 20, 24, 28); + titleLabelFontSizeComboBox.valueProperty().addListener((a, b, c) -> + { + try { + layout.setTitleLabelFontSize(c); + titleLabelFontSizeComboBox.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + } catch (NumberFormatException e) { + titleLabelFontSizeComboBox.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + }); + titleLabelFontSizeComboBox.setConverter(new IntegerStringConverter()); + + programLayoutComboBox.getItems().addAll(Theme.values()); + programLayoutComboBox.setButtonCell(new ThemeCell()); + programLayoutComboBox.setCellFactory(list -> new ThemeCell()); + programLayoutComboBox.valueProperty().addListener((a, b, c) -> + { + if (b != null) { + layout.setBackgroundColor(c.getBackground()); + layout.setAccentColor(c.getGridColor()); + backgroundColorPicker.setValue(c.getBackground()); + accentColorChooser.setValue(c.getGridColor()); + } + }); + accentColorChooser.valueProperty().addListener((a, b, c) -> + { + layout.setAccentColor(c); + }); + customLayoutCheckBox.selectedProperty().addListener((a, b, c) -> + { + layout.setCustomLayout(c); + customizeView.setDisable(!c); + }); + } + + public void setLayout(ClassicGlobalLayout defaultLayout) { + this.layout = defaultLayout; + + backgroundColorPicker.setValue(layout.getBackgroundColor()); + playgroundColorPicker.setValue(layout.getPlaybackColor()); + warnColorPicker.setValue(layout.getWarnColor()); + fadeColorPicker.setValue(layout.getFadeColor()); + + infoLabelColorPicker.setValue(layout.getInfoLabelColor()); + infoLabelFontSizeComboBox.setValue(layout.getInfoLabelFontSize()); + + titleLabelColorPicker.setValue(layout.getTitleLabelColor()); + titleLabelFontSizeComboBox.setValue(layout.getTitleLabelFontSize()); + } + + @FXML + private void resetButtonHandler(ActionEvent event) { + layout.reset(); + setLayout(layout); + } + + @Override + public void updateData() { + backgroundColorPicker.setValue(layout.getBackgroundColor()); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutCartViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutCartViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..dd3e7bd2cfe6f21f8ab1fbe39d609185c2cb9930 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutCartViewController.java @@ -0,0 +1,99 @@ +package de.tobias.playpad.viewcontroller.layout; + +import java.util.function.Consumer; + +import org.controlsfx.control.PopOver; +import org.controlsfx.control.PopOver.ArrowLocation; + +import de.tobias.playpad.DisplayableColor; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.modern.ModernColor; +import de.tobias.playpad.layout.modern.ModernLayoutCart; +import de.tobias.playpad.view.ColorView; +import de.tobias.playpad.viewcontroller.CartLayoutViewController; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; + +public class ModernLayoutCartViewController extends CartLayoutViewController { + + @FXML private Button backgroundColorButton; + @FXML private Button playColorButton; + @FXML private CheckBox warnAnimationCheckBox; + + @FXML private Button resetButton; + + private ModernLayoutCart cartLayout; + + private PopOver colorChooser; + + public ModernLayoutCartViewController(CartLayout layout) { + super("modernLayoutCart", "de/tobias/playpad/assets/view/option/layout/", PlayPadMain.getUiResourceBundle(), layout); + + if (layout instanceof CartLayout) { + this.cartLayout = (ModernLayoutCart) layout; + + setLayout(); + } + } + + private void setLayout() { + backgroundColorButton.setStyle(getLinearGradientCss(cartLayout.getBackgroundColor())); + playColorButton.setStyle(getLinearGradientCss(cartLayout.getPlayColor())); + + warnAnimationCheckBox.setSelected(cartLayout.isWarnAnimation()); + } + + @Override + public void init() { + warnAnimationCheckBox.selectedProperty().addListener((a, b, c) -> + { + cartLayout.setWarnAnimation(c); + }); + } + + @FXML + private void resetButtonHandler(ActionEvent event) { + cartLayout.reset(); + setLayout(); + } + + @FXML + private void backgroundColorButtonHandler(ActionEvent event) { + colorChooser(backgroundColorButton, cartLayout.getBackgroundColor(), (color) -> cartLayout.setBackgroundColor(color)); + } + + @FXML + private void playColorButtonHandler(ActionEvent event) { + colorChooser(playColorButton, cartLayout.getPlayColor(), (color) -> cartLayout.setPlayColor(color)); + } + + private void colorChooser(Button anchorNode, ModernColor startColor, Consumer<ModernColor> onFinish) { + ColorView view = new ColorView(startColor, ModernColor.values(), (DisplayableColor t) -> + { + colorChooser.hide(); + + if (t instanceof ModernColor) { + ModernColor color = (ModernColor) t; + onFinish.accept(color); + anchorNode.setStyle(getLinearGradientCss(color)); + } + }); + colorChooser = new PopOver(); + colorChooser.setContentNode(view); + colorChooser.setDetachable(false); + colorChooser.setOnHiding(e -> colorChooser = null); + colorChooser.setCornerRadius(5); + colorChooser.setArrowLocation(ArrowLocation.LEFT_CENTER); + colorChooser.show(anchorNode); + } + + private String getLinearGradientCss(ModernColor color) { + String css = "-fx-background-color: " + color.linearGradient() + ";"; + css += "-fx-border-color: rgb(20, 20, 20);-fx-border-width: 1.5px;-fx-border-radius: 3px;"; + return css; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutGlobalViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutGlobalViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..bbda3b0d30dddff4c980f601cd70b1bb8876fc15 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/layout/ModernLayoutGlobalViewController.java @@ -0,0 +1,122 @@ +package de.tobias.playpad.viewcontroller.layout; + +import java.util.function.Consumer; + +import org.controlsfx.control.PopOver; +import org.controlsfx.control.PopOver.ArrowLocation; + +import de.tobias.playpad.DisplayableColor; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.modern.ModernColor; +import de.tobias.playpad.layout.modern.ModernLayoutGlobal; +import de.tobias.playpad.view.ColorView; +import de.tobias.playpad.viewcontroller.GlobalLayoutViewController; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.util.converter.IntegerStringConverter; + +public class ModernLayoutGlobalViewController extends GlobalLayoutViewController { + + @FXML private Button backgroundColorButton; + @FXML private Button playColorButton; + + @FXML private CheckBox warnAnimationCheckBox; + + @FXML private ComboBox<Integer> infoLabelFontSizeComboBox; + @FXML private ComboBox<Integer> titleLabelFontSizeComboBox; + + @FXML private Button resetButton; + + private ModernLayoutGlobal globalLayout; + + private PopOver colorChooser; + + public ModernLayoutGlobalViewController(GlobalLayout layout) { + super("modernLayoutGlobal", "de/tobias/playpad/assets/view/option/layout/", PlayPadMain.getUiResourceBundle(), layout); + + if (layout instanceof GlobalLayout) { + this.globalLayout = (ModernLayoutGlobal) layout; + + setLayout(); + } + } + + private void setLayout() { + backgroundColorButton.setStyle(getLinearGradientCss(globalLayout.getBackgroundColor())); + playColorButton.setStyle(getLinearGradientCss(globalLayout.getPlayColor())); + + warnAnimationCheckBox.setSelected(globalLayout.isWarnAnimation()); + + infoLabelFontSizeComboBox.setValue(globalLayout.getInfoFontSize()); + titleLabelFontSizeComboBox.setValue(globalLayout.getTitleFontSize()); + } + + @Override + public void init() { + warnAnimationCheckBox.selectedProperty().addListener((a, b, c) -> + { + globalLayout.setWarnAnimation(c); + }); + + infoLabelFontSizeComboBox.getItems().addAll(9, 10, 12, 13, 14, 16, 18, 20, 24, 28); + infoLabelFontSizeComboBox.valueProperty().addListener((a, b, c) -> + { + globalLayout.setInfoFontSize(c); + }); + infoLabelFontSizeComboBox.setConverter(new IntegerStringConverter()); + + titleLabelFontSizeComboBox.getItems().addAll(9, 10, 12, 13, 14, 16, 18, 20, 24, 28); + titleLabelFontSizeComboBox.valueProperty().addListener((a, b, c) -> + { + globalLayout.setTitleFontSize(c); + }); + titleLabelFontSizeComboBox.setConverter(new IntegerStringConverter()); + } + + @FXML + private void resetButtonHandler(ActionEvent event) { + globalLayout.reset(); + setLayout(); + } + + @FXML + private void backgroundColorButtonHandler(ActionEvent event) { + colorChooser(backgroundColorButton, globalLayout.getBackgroundColor(), (color) -> globalLayout.setBackgroundColor(color)); + } + + @FXML + private void playColorButtonHandler(ActionEvent event) { + colorChooser(playColorButton, globalLayout.getPlayColor(), (color) -> globalLayout.setPlayColor(color)); + } + + private void colorChooser(Button anchorNode, ModernColor startColor, Consumer<ModernColor> onFinish) { + ColorView view = new ColorView(startColor, ModernColor.values(), (DisplayableColor t) -> + { + colorChooser.hide(); + + if (t instanceof ModernColor) { + ModernColor color = (ModernColor) t; + onFinish.accept(color); + anchorNode.setStyle(getLinearGradientCss(color)); + } + }); + colorChooser = new PopOver(); + colorChooser.setContentNode(view); + colorChooser.setDetachable(false); + colorChooser.setOnHiding(e -> colorChooser = null); + colorChooser.setCornerRadius(5); + colorChooser.setArrowLocation(ArrowLocation.LEFT_CENTER); + colorChooser.show(anchorNode); + } + + private String getLinearGradientCss(ModernColor color) { + String css = "-fx-background-color: " + color.linearGradient() + ";"; + css += "-fx-border-color: rgb(20, 20, 20);-fx-border-width: 1.5px;-fx-border-radius: 3px;"; + return css; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainMenuBarController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainMenuBarController.java new file mode 100644 index 0000000000000000000000000000000000000000..e905a558857e8aa68ed3260bf968260addc08539 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainMenuBarController.java @@ -0,0 +1,361 @@ +package de.tobias.playpad.viewcontroller.main; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Optional; +import java.util.ResourceBundle; + +import de.tobias.playpad.AppUserInfoStrings; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.connect.CartActionConnect; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.project.ProjectNotFoundException; +import de.tobias.playpad.project.ProjectReference; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileNotFoundException; +import de.tobias.playpad.viewcontroller.PluginViewController; +import de.tobias.playpad.viewcontroller.PrintDialog; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.dialog.ErrorSummaryDialog; +import de.tobias.playpad.viewcontroller.dialog.ImportDialog; +import de.tobias.playpad.viewcontroller.dialog.NewProjectDialog; +import de.tobias.playpad.viewcontroller.dialog.ProfileViewController; +import de.tobias.playpad.viewcontroller.dialog.ProjectManagerDialog; +import de.tobias.playpad.viewcontroller.option.SettingsViewController; +import de.tobias.playpad.viewcontroller.pad.PadDragListener; +import de.tobias.utils.application.ApplicationInfo; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.OS; +import de.tobias.utils.util.OS.OSType; +import de.tobias.utils.util.Worker; +import de.tobias.utils.util.net.FileUpload; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.CheckMenuItem; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; +import javafx.stage.Modality; +import javafx.stage.Stage; +import net.xeoh.plugins.base.PluginManager; + +public class MainMenuBarController implements EventHandler<ActionEvent>, Initializable { + + @FXML private MenuBar menuBar; + @FXML CheckMenuItem dndModeMenuItem; + @FXML CheckMenuItem alwaysOnTopItem; + @FXML CheckMenuItem fullScreenMenuItem; + @FXML Menu recentOpenMenu; + @FXML MenuItem profileMenu; + + @FXML CheckMenuItem quickEditMenuItem; + @FXML MenuItem settingsMenuItem; + + @FXML Menu extensionMenu; + + // Open Windows + private SettingsViewController settingsViewController; + private PluginManager manager; + private MainViewController mvc; + + @Override + public void initialize(URL location, ResourceBundle resources) { + menuBar.setUseSystemMenuBar(true); + + if (OS.getType() == OSType.MacOSX) { + menuBar.setMaxHeight(0); + } + } + + // Event + @FXML + private void newDocumentHandler(ActionEvent event) { + doAction(() -> + { + NewProjectDialog dialog = new NewProjectDialog(mvc.getStage()); + dialog.getStage().showAndWait(); + + Project project = dialog.getProject(); + if (project != null) { + mvc.setProject(project); + mvc.showPage(0); + } + }); + } + + @FXML + private void openDocumentHandler(ActionEvent event) { + doAction(() -> + { + ProjectManagerDialog view = new ProjectManagerDialog(mvc.getStage(), mvc.getProject()); + Optional<ProjectReference> result = view.showAndWait(); + if (result.isPresent()) { + ProjectReference ref = result.get(); + try { + Project project = Project.load(result.get(), true, ImportDialog.getInstance(mvc.getStage())); + mvc.setProject(project); + + mvc.showPage(0); + createRecentDocumentMenuItems(); + } catch (ProfileNotFoundException e) { + e.printStackTrace(); + mvc.showErrorMessage( + Localization.getString(Strings.Error_Profile_NotFound, ref.getProfileReference(), e.getLocalizedMessage())); + + // Neues Profile wählen + Profile profile = ImportDialog.getInstance(mvc.getStage()).getUnkownProfile(); + ref.setProfileReference(profile.getRef()); + } catch (ProjectNotFoundException e) { + e.printStackTrace(); + mvc.showErrorMessage(Localization.getString(Strings.Error_Project_NotFound, ref, e.getLocalizedMessage())); + } catch (Exception e) { + e.printStackTrace(); + mvc.showErrorMessage(Localization.getString(Strings.Error_Project_Open, ref, e.getLocalizedMessage())); + } + } + }); + } + + @FXML + private void saveMenuHandler(ActionEvent event) { + try { + mvc.getProject().save(); + mvc.notify(Localization.getString(Strings.Standard_File_Save), PlayPadMain.notificationDisplayTimeMillis); + } catch (IOException e) { + mvc.showError(Localization.getString(Strings.Error_Project_Save)); + e.printStackTrace(); + } + } + + // Einstellungsmenu + @FXML + private void profileMenuHandler(ActionEvent event) { + doAction(() -> + { + ProfileViewController controller = new ProfileViewController(mvc.getStage(), mvc.getProject()); + controller.getStage().showAndWait(); + }); + } + + @FXML + private void quickEditMenuHandler(ActionEvent event) { + try { + for (Action action : Profile.currentProfile().getMappings().getActiveMapping().getActionsOfType(CartActionConnect.TYPE)) { + CartAction cartAction = (CartAction) action; + if (cartAction.getCart() < mvc.padViewList.size()) { + cartAction.getPad().getController().getParent().setBusy(quickEditMenuItem.isSelected()); + // IPadViewController controller = mvc.padViewList.get(cartAction.getCart()); + // MapperQuickSettingsView view = new MapperQuickSettingsView((Pane) controller.getParent().getParent()); + // view.showDropOptions(action.getMappers()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @FXML + private void settingsHandler(ActionEvent event) { + Midi midi = Midi.getInstance(); + + if (settingsViewController == null) { + settingsViewController = new SettingsViewController(midi, mvc.getScreen(), mvc.getStage(), mvc.getProject()) { + + @Override + public void updateData() { + midi.setListener(mvc.getMidiHandler()); + + boolean change = false; + for (SettingsTabViewController controller : tabs) { + if (controller.needReload()) { + change = true; + controller.reload(Profile.currentProfile(), mvc.getProject(), mvc); + } + } + + if (change) { + PlayPadPlugin.getImplementation().getSettingsListener().forEach(l -> l.onChange(Profile.currentProfile())); + } + + settingsViewController = null; + mvc.getStage().toFront(); + } + }; + + settingsViewController.getStage().show(); + } else if (settingsViewController.getStage().isShowing()) { + settingsViewController.getStage().toFront(); + } + } + + @FXML + private void printMenuHandler(ActionEvent event) { + PrintDialog dialog = new PrintDialog(mvc.getProject(), mvc.getStage()); + dialog.getStage().show(); + } + + @FXML + private void alwaysOnTopItemHandler(ActionEvent event) { + mvc.getStage().setAlwaysOnTop(alwaysOnTopItem.isSelected()); + Profile.currentProfile().getProfileSettings().setWindowAlwaysOnTop(alwaysOnTopItem.isSelected()); + } + + @FXML + private void fullScreenMenuItemHandler(ActionEvent event) { + mvc.getStage().setFullScreen(fullScreenMenuItem.isSelected()); + } + + @FXML + private void dndModeHandler(ActionEvent event) { + if (dndModeMenuItem.isSelected()) { + doAction(() -> + { + PadDragListener.setDndMode(true); + for (IPadViewController view : mvc.padViewList) { + view.showDnDLayout(true); + } + }); + } else { + PadDragListener.setDndMode(false); + for (IPadViewController view : mvc.padViewList) { + view.showDnDLayout(false); + } + } + } + + @FXML + private void errorMenuHandler(ActionEvent event) { + ErrorSummaryDialog.getInstance().getStage().show(); + } + + @FXML + private void aboutMenuHandler(ActionEvent event) { + ApplicationInfo info = ApplicationUtils.getApplication().getInfo(); + String message = Localization.getString(Strings.UI_Dialog_Info_Content, info.getVersion(), info.getBuild(), info.getAuthor()); + mvc.showInfoMessage(message, Localization.getString(Strings.UI_Dialog_Info_Header, info.getName()), PlayPadMain.stageIcon.orElse(null)); + } + + @FXML + private void visiteWebsiteMenuHandler(ActionEvent event) { + String website = ApplicationUtils.getApplication().getInfo().getUserInfo().getString(AppUserInfoStrings.WEBSITE); + try { + Desktop.getDesktop().browse(new URI(website)); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + + @FXML + private void sendErrorMenuItem(ActionEvent event) { + Alert alert = new Alert(AlertType.INFORMATION); + alert.initOwner(mvc.getStage()); + alert.initModality(Modality.WINDOW_MODAL); + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + alert.setContentText(Localization.getString(Strings.UI_Dialog_Feedback_Content)); + alert.show(); + + Worker.runLater(() -> + { + try { + String response = FileUpload.fileUpload( + ApplicationUtils.getApplication().getInfo().getUserInfo().getString(AppUserInfoStrings.ERROR_URL), + ApplicationUtils.getApplication().getPath(PathType.LOG, "err.log").toFile()); + Platform.runLater(() -> alert.setContentText(response)); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + @FXML + private void pluginMenuItemHandler(ActionEvent e) { + doAction(() -> + { + PluginViewController controller = new PluginViewController(manager, mvc.getStage()); + controller.getStage().showAndWait(); + mvc.showPage(mvc.getPage()); + }); + } + + @Override + public void handle(ActionEvent event) { + if (event.getSource() instanceof MenuItem) { + // Zuletzt verwendete Projects + doAction(() -> + { + MenuItem item = (MenuItem) event.getSource(); + ProjectReference ref = (ProjectReference) item.getUserData(); + try { + // Speichern das alte Project in mvc.setProject(Project) + Project project = Project.load(ref, true, ImportDialog.getInstance(mvc.getStage())); + mvc.setProject(project); + mvc.showPage(0); + } catch (ProfileNotFoundException e) { + e.printStackTrace(); + mvc.showErrorMessage( + Localization.getString(Strings.Error_Profile_NotFound, ref.getProfileReference(), e.getLocalizedMessage())); + + // Neues Profile wählen + Profile profile = ImportDialog.getInstance(mvc.getStage()).getUnkownProfile(); + ref.setProfileReference(profile.getRef()); + } catch (ProjectNotFoundException e) { + e.printStackTrace(); + mvc.showErrorMessage(Localization.getString(Strings.Error_Project_NotFound, ref, e.getLocalizedMessage())); + } catch (Exception e) { + e.printStackTrace(); + mvc.showErrorMessage(Localization.getString(Strings.Error_Project_Open, ref, e.getLocalizedMessage())); + } + }); + } + } + + private void doAction(Runnable run) { + if (mvc.getProject().getPlayedPlayers() > 0 && Profile.currentProfile().getProfileSettings().isLiveMode()) { + mvc.showLiveInfo(); + } else { + run.run(); + } + } + + private final int LAST_DOCUMENT_LIMIT = 3; + + public void createRecentDocumentMenuItems() { + recentOpenMenu.getItems().clear(); + + String project = mvc.getProject().getRef().getName(); + + ProjectReference.getProjectsSorted().stream().filter(item -> !item.getName().equals(project)).limit(LAST_DOCUMENT_LIMIT).forEach(item -> + { + MenuItem menuItem = new MenuItem(item.toString()); + menuItem.setUserData(item); + menuItem.setOnAction(this); + recentOpenMenu.getItems().add(menuItem); + }); + } + + public void setPluginManager(PluginManager manager) { + this.manager = manager; + } + + public void setMainViewController(MainViewController mvc) { + this.mvc = mvc; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainToolbarController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainToolbarController.java new file mode 100644 index 0000000000000000000000000000000000000000..3b582c60879890a4c9184769cdb0d7f3eba2f68a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainToolbarController.java @@ -0,0 +1,88 @@ +package de.tobias.playpad.viewcontroller.main; + +import java.net.URL; +import java.util.ResourceBundle; + +import de.tobias.playpad.Strings; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.main.IMainToolbarViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.scene.control.ToolBar; +import javafx.scene.layout.HBox; + +public class MainToolbarController implements IMainToolbarViewController, Initializable, EventHandler<ActionEvent> { + + @FXML private ToolBar toolbar; + @FXML private HBox toolbarHBox; + @FXML private HBox pageHBox; + + @FXML private Label volumeDownLabel; + @FXML private Slider volumeSlider; + @FXML private Label volumeUpLabel; + + private MainViewController mainViewController; + + @Override + public void initialize(URL location, ResourceBundle resources) { + + // HBox Child wird Max Width, subtract weil sonst zu groß für Toolbar + toolbarHBox.prefWidthProperty().bind(toolbar.widthProperty().subtract(25)); + toolbarHBox.prefHeightProperty().bind(toolbar.minHeightProperty()); + + // Icons Volume + volumeDownLabel.setGraphic(new FontIcon("volume-item", FontAwesomeType.VOLUME_DOWN)); + volumeUpLabel.setGraphic(new FontIcon("volume-item", FontAwesomeType.VOLUME_UP)); + + volumeSlider.setOnScroll(ev -> + { + volumeSlider.setValue(volumeSlider.getValue() - ev.getDeltaY() * 0.001); + volumeSlider.setValue(volumeSlider.getValue() + ev.getDeltaX() * 0.001); + }); + } + + public void createPageButtons() { + pageHBox.getChildren().clear(); + for (int i = 0; i < Profile.currentProfile().getProfileSettings().getPageCount(); i++) { + Button item = new Button(Localization.getString(Strings.UI_Window_Main_PageButton, (i + 1))); + item.setUserData(i); + item.setFocusTraversable(false); + item.setOnAction(this); + pageHBox.getChildren().add(item); + } + } + + public HBox getPageHBox() { + return pageHBox; + } + + public HBox getToolbarHBox() { + return toolbarHBox; + } + + public Slider getVolumeSlider() { + return volumeSlider; + } + + public void setMainViewController(MainViewController mainViewController) { + this.mainViewController = mainViewController; + } + + @Override + public void handle(ActionEvent event) { + if (event.getSource() instanceof Button) { + // Page Buttons + Button item = (Button) event.getSource(); + int number = (int) item.getUserData(); + mainViewController.showPage(number); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..a1811badf7ce2fcbf7173269c3502048bc7b70f7 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/main/MainViewController.java @@ -0,0 +1,645 @@ +package de.tobias.playpad.viewcontroller.main; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.sound.midi.MidiUnavailableException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.cartaction.CartAction; +import de.tobias.playpad.action.connect.CartActionConnect; +import de.tobias.playpad.action.feedback.ColorAssociator; +import de.tobias.playpad.action.feedback.DisplayableFeedbackColor; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MapperFeedbackable; +import de.tobias.playpad.action.mapper.listener.KeyboardHandler; +import de.tobias.playpad.action.mapper.listener.MidiHandler; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.LayoutColorAssociator; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.plugin.WindowListener; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileListener; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.view.PadView; +import de.tobias.playpad.viewcontroller.IPadView; +import de.tobias.playpad.viewcontroller.dialog.ErrorSummaryDialog; +import de.tobias.playpad.viewcontroller.pad.PadDragListener; +import de.tobias.playpad.viewcontroller.pad.PadViewController; +import de.tobias.utils.ui.BasicControllerSettings; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.ui.scene.NotificationPane; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.OS; +import de.tobias.utils.util.OS.OSType; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.Slider; +import javafx.scene.input.KeyCombination; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.RowConstraints; +import javafx.scene.paint.Color; +import javafx.scene.shape.Line; +import javafx.stage.Modality; +import javafx.stage.Screen; +import javafx.stage.Stage; +import net.xeoh.plugins.base.PluginManager; + +public class MainViewController extends ViewController implements IMainViewController, NotificationHandler, ProfileListener { + + private static final String CURRENT_PAGE_BUTTON = "current-page-button"; + + // UI + @FXML protected MainMenuBarController menuBarController; + @FXML protected MainToolbarController toolbarController; + @FXML private GridPane padGridPane; + + @FXML private Label liveLabel; + + @FXML private AnchorPane gridContainer; + private NotificationPane notificationPane; + + private ErrorSummaryDialog errorSummaryDialog; + + // Model + private Project project; + protected List<IPadViewController> padViewList = new ArrayList<>(); + + // Current View Items + private int pageNumber; + + // Mapper + private Midi midi; + private MidiHandler midiHandler; + private KeyboardHandler keyboardHandler; + + // Style + private Color gridColor; + + public MainViewController(Project project, List<WindowListener<IMainViewController>> listener, PluginManager manager) { + super("mainView", "de/tobias/playpad/assets/view/main/", null, PlayPadMain.getUiResourceBundle()); + + // Include FXML Setup + toolbarController.setMainViewController(this); + menuBarController.setMainViewController(this); + menuBarController.setPluginManager(manager); + + padGridPane.setGridLinesVisible(true); + + // Settings Setup + Profile.registerListener(this); + + /* + * Gridline Color + */ + try { + Field field = padGridPane.getClass().getDeclaredField("gridLines"); + field.setAccessible(true); + Group group = (Group) field.get(padGridPane); + if (group != null) { + group.getChildren().addListener((javafx.collections.ListChangeListener.Change<? extends Node> c) -> + { + for (Node node : group.getChildren()) { + if (node instanceof Line) { + ((Line) node).setStroke(gridColor); + } + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + } + + /* + * Mapper Setup & Listener + */ + this.midi = Midi.getInstance(); + this.midiHandler = new MidiHandler(midi, this, project); + this.midi.setListener(midiHandler); + this.keyboardHandler = new KeyboardHandler(project, this); + + // Setup + errorSummaryDialog = new ErrorSummaryDialog(getStage()); + getStage().toFront(); + + // setup project + setProject(project); + + // Setup Settings + reloadSettings(null, Profile.currentProfile()); + + listener.forEach(l -> l.onInit(this)); + } + + @Override + public void init() { + padGridPane.getStyleClass().add("pad-grid"); + + menuBarController.extensionMenu.setVisible(false); + + liveLabel.setVisible(false); + liveLabel.getStyleClass().add("live-label"); + + notificationPane = new NotificationPane(padGridPane); + notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK); + + gridContainer.getChildren().add(notificationPane); + setAnchor(notificationPane, 0, 0, 0, 0); + + getStage().fullScreenProperty().addListener((a, b, c) -> + { + menuBarController.fullScreenMenuItem.setSelected(c); + }); + + // Lautstärke Veränderung + toolbarController.getVolumeSlider().valueProperty().addListener((a, b, c) -> + { + setPadVolume(c.doubleValue()); + }); + } + + private void setPadVolume(double volume) { + for (Pad pad : project.getPads().values()) { + pad.setMasterVolume(volume); + } + } + + private void setTitle() { + if (project != null && Profile.currentProfile() != null) { + getStage().setTitle(Localization.getString(Strings.UI_Window_Main_Title, project.getRef().getName(), + Profile.currentProfile().getRef().getName())); + } else { + getStage().setTitle(Localization.getString(Strings.UI_Window_Main_Title)); + } + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + stage.setFullScreenExitKeyCombination(KeyCombination.keyCombination(KeyCombination.SHIFT_DOWN + "+Esc")); + stage.setTitle(Localization.getString(Strings.UI_Window_Main_Title)); + stage.show(); + } + + @Override + protected void loadSettings(BasicControllerSettings settings) { + List<Screen> screens = Screen.getScreensForRectangle(settings.getUserInfoAsDouble("x"), settings.getUserInfoAsDouble("y"), + settings.width, settings.height); + if (!screens.isEmpty()) { + getStage().setX(settings.getUserInfoAsDouble("x")); + getStage().setY(settings.getUserInfoAsDouble("y")); + } + + getStage().setWidth(settings.width); + getStage().setHeight(settings.height); + } + + @Override + protected void save(BasicControllerSettings settings) { + settings.addUserInfo("x", getStage().getX()); + settings.addUserInfo("y", getStage().getY()); + settings.width = getStage().getWidth(); + settings.height = getStage().getHeight(); + } + + public void setProject(Project project) { + if (this.project != null) { + for (IPadViewController controller : padViewList) { + controller.unconnectPad(); + } + try { + this.project.save(); + } catch (IOException e) { + e.printStackTrace(); + showError(Localization.getString(Strings.Error_Project_Save, e.getLocalizedMessage())); + } + } + this.project = project; + + midiHandler.setProject(project); + keyboardHandler.setProject(project); + PadDragListener.setProject(project); + + errorSummaryDialog.setProject(project); + menuBarController.createRecentDocumentMenuItems(); + setTitle(); + } + + // GUI Helping Methoden + public void loadUserCss() { + Profile.currentProfile().currentLayout().applyCssMainView(this, getStage(), project); + applyColorsToMappers(); + } + + private void applyColorsToMappers() { + // Apply Layout to Mapper + List<CartAction> actions = Profile.currentProfile().getMappings().getActiveMapping().getActions(CartActionConnect.TYPE); + for (CartAction cartAction : actions) { + if (cartAction.isAutoFeedbackColors()) { + for (Mapper mapper : cartAction.getMappers()) { + if (mapper instanceof MapperFeedbackable) { + MapperFeedbackable feedbackable = (MapperFeedbackable) mapper; + if (feedbackable.supportFeedback() && mapper instanceof ColorAssociator) { + ColorAssociator colorAssociator = (ColorAssociator) mapper; + + Pad pad = project.getPad(cartAction.getCart()); + Color layoutStandardColor = null; + Color layoutEventColor = null; + + if (pad.isCustomLayout()) { + CartLayout layout = pad.getLayout(); + if (layout instanceof LayoutColorAssociator) { + layoutStandardColor = ((LayoutColorAssociator) layout).getAssociatedStandardColor(); + layoutEventColor = ((LayoutColorAssociator) layout).getAssociatedEventColor(); + } + } else { + GlobalLayout layout = Profile.currentProfile().currentLayout(); + if (layout instanceof LayoutColorAssociator) { + layoutStandardColor = ((LayoutColorAssociator) layout).getAssociatedStandardColor(); + layoutEventColor = ((LayoutColorAssociator) layout).getAssociatedEventColor(); + } + } + + if (layoutStandardColor != null) { + DisplayableFeedbackColor associator = Mapper.searchColor(colorAssociator, FeedbackMessage.STANDARD, + layoutStandardColor); + colorAssociator.setColor(FeedbackMessage.STANDARD, associator.midiVelocity()); + } + + if (layoutEventColor != null) { + DisplayableFeedbackColor associator = Mapper.searchColor(colorAssociator, FeedbackMessage.EVENT, + layoutEventColor); + colorAssociator.setColor(FeedbackMessage.EVENT, associator.midiVelocity()); + } + } + } + } + } + } + } + + /** + * Erstellt Constraints von GridView, Erstellt PadViews, Lädt CSS, Set Min Size vom Fendster + */ + public void createPadViews() { + ProfileSettings profileSettings = Profile.currentProfile().getProfileSettings(); + + // Table + padGridPane.getColumnConstraints().clear(); + double xPercentage = 1.0 / (double) profileSettings.getColumns(); + for (int i = 0; i < profileSettings.getColumns(); i++) { + ColumnConstraints c = new ColumnConstraints(); + c.setPercentWidth(xPercentage * 100); + padGridPane.getColumnConstraints().add(c); + } + + padGridPane.getRowConstraints().clear(); + double yPercentage = 1.0 / (double) profileSettings.getRows(); + for (int i = 0; i < profileSettings.getRows(); i++) { + RowConstraints c = new RowConstraints(); + c.setPercentHeight(yPercentage * 100); + padGridPane.getRowConstraints().add(c); + } + + // Pads - Remove Old PadViews + padGridPane.getChildren().removeIf(t -> + { + if (t instanceof PadView) { + ((PadView) t).getController().unconnectPad(); + return true; + } else { + return false; + } + }); + padViewList.clear(); + + // Neue PadViews + for (int y = 0; y < profileSettings.getRows(); y++) { + for (int x = 0; x < profileSettings.getColumns(); x++) { + IPadViewController controller = new PadViewController(); + IPadView node = controller.getParent(); + if (node instanceof PadView) { + padGridPane.add((Node) node, x, y); + padViewList.add(controller); + } + } + } + + // Min Size of window + getStage().setMinWidth(Profile.currentProfile().currentLayout().getMinWidth(profileSettings.getColumns())); + if (OS.getType() == OSType.MacOSX) { + getStage().setMinHeight(Profile.currentProfile().currentLayout().getMinHeight(profileSettings.getRows()) + 100); + } else { + getStage().setMinHeight(Profile.currentProfile().currentLayout().getMinHeight(profileSettings.getRows()) + 150); + } + } + + /** + * Setzt die Pads in die Views und Cleared die alten Views. Lädt für die neuen Pads das Layout neu. + * + * @param newPage + */ + public synchronized void showPage(int newPage) { + ProfileSettings profileSettings = Profile.currentProfile().getProfileSettings(); + + if (!(newPage >= 0 && newPage < profileSettings.getPageCount())) { + return; + } + + // Button in Toolbar + Button oldButton = (Button) toolbarController.getPageHBox().getChildren().get(pageNumber); // Der Aktuell andersfarbende Button + oldButton.getStyleClass().remove(CURRENT_PAGE_BUTTON); + + this.pageNumber = newPage; + + // alte Pads weg + padViewList.forEach(i -> i.unconnectPad()); + + // Neue Pads anzeigen + int index = pageNumber * profileSettings.getRows() * profileSettings.getColumns(); + for (int i = 0; i < profileSettings.getRows() * profileSettings.getColumns(); i++) { + if (padViewList.size() > i) { + IPadViewController view = padViewList.get(i); + view.setPad(project.getPad(index)); + } + index++; + } + + // Button in Toolbar anders färben + Button newButton = (Button) toolbarController.getPageHBox().getChildren().get(pageNumber); + newButton.getStyleClass().add(CURRENT_PAGE_BUTTON); + + // Handle Mapper + if (Profile.currentProfile() != null) { + Profile.currentProfile().getMappings().getActiveMapping().showFeedback(project, this); + } + + // GUI Styling + loadUserCss(); + } + + public Slider getVolumeSlider() { + return toolbarController.getVolumeSlider(); + } + + @Override + public boolean closeRequest() { + if (errorSummaryDialog != null) + errorSummaryDialog.getStage().close(); + + if (Profile.currentProfile() != null) { + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + + // Frag den Nutzer ob das Programm wirdklich geschlossen werden sol wenn ein Pad noch im Status Play ist + if (project.getPlayedPlayers() > 0 && profilSettings.isLiveMode()) { + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setContentText(Localization.getString(Strings.UI_Window_Main_CloseRequest)); + + alert.initOwner(getStage()); + alert.initModality(Modality.WINDOW_MODAL); + Stage alertStage = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(alertStage.getIcons()::add); + + Optional<ButtonType> result = alert.showAndWait(); + if (result.isPresent()) + if (result.get() != ButtonType.OK) + return false; + } + + // MIDI Shutdown + if (profilSettings.isMidiActive()) { + try { + midi.close(); + } catch (MidiUnavailableException e1) { + e1.printStackTrace(); + } + } + } + + if (getStage().isIconified()) { + getStage().setIconified(false); + } + + // Verbindung von Pad und PadView wird getrennt. Zudem wird bei PLAY oder PAUSE auf STOP gesetzt + padViewList.forEach(padView -> padView.unconnectPad()); + + Worker.shutdown(); + + // Mapper Clear Feedback + Profile.currentProfile().getMappings().getActiveMapping().clearFeedback(); + + saveSettings(); + + System.exit(0); + return true; + } + + /* + * MIDI + */ + + /** + * Init MIDI Device by using the Midi Class and show some feedback the user. + * + * @param name + * Device Name + * + * @see Midi#lookupMidiDevice(String) + */ + private void loadMidiDevice(String name) { + try { + midi.lookupMidiDevice(name); + notificationPane.showAndHide(Localization.getString(Strings.Info_Midi_Device_Connected, name), + PlayPadMain.notificationDisplayTimeMillis); + } catch (NullPointerException e) { + showError(Localization.getString(Strings.Error_Midi_Device_Unavailible, name)); + } catch (IllegalArgumentException | MidiUnavailableException e) { + showError(Localization.getString(Strings.Error_Midi_Device_Busy, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + + @Override + public void notify(String text, long duration) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration)); + } + } + + @Override + public void notify(String text, long duration, Runnable finish) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration, finish); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration, finish)); + } + } + + @Override + public void showError(String message) { + if (Platform.isFxApplicationThread()) { + notificationPane.showError(message); + } else { + Platform.runLater(() -> notificationPane.showError(message)); + } + } + + @Override + public void hide() { + if (Platform.isFxApplicationThread()) { + notificationPane.hide(); + } else { + Platform.runLater(() -> notificationPane.hide()); + } + } + + @Override + public int getPage() { + return pageNumber; + } + + private boolean shown = false; + + protected void showLiveInfo() { + if (!shown) { + toolbarController.getToolbarHBox().setOpacity(0.5); + liveLabel.setVisible(true); + shown = true; + Worker.runLater(() -> + { + try { + Thread.sleep(PlayPadMain.notificationDisplayTimeMillis * 2); + } catch (Exception e) {} + Platform.runLater(() -> + { + toolbarController.getToolbarHBox().setOpacity(1); + liveLabel.setVisible(false); + shown = false; + }); + }); + } + } + + @Override + public void reloadSettings(Profile old, Profile currentProfile) { + if (old != null) { + // Unbind Volume Slider + toolbarController.getVolumeSlider().valueProperty().unbindBidirectional(old.getProfileSettings().volumeProperty()); + // Clear Feedback on Devie (LaunchPad Light off) + old.getMappings().getActiveMapping().getActions().forEach(action -> action.clearFeedback()); + } + + // Pad iund Page GUI + createPadViews(); + toolbarController.createPageButtons(); + + // Volume + toolbarController.getVolumeSlider().valueProperty().bindBidirectional(currentProfile.getProfileSettings().volumeProperty()); + + // Apply Layout + currentProfile.currentLayout().applyCssMainView(this, getStage(), project); + + // MIDI + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + if (profilSettings.isMidiActive()) { + // Load known MIDI Device + Worker.runLater(() -> + { + if (profilSettings.getMidiDevice() != null) { + loadMidiDevice(profilSettings.getMidiDevice()); + + applyColorsToMappers(); + + Platform.runLater(() -> + { + // Handle Mapper + if (Profile.currentProfile() != null) { + Profile.currentProfile().getMappings().getActiveMapping().initFeedback(); + Profile.currentProfile().getMappings().getActiveMapping().showFeedback(project, this); + } + }); + } + }); + } + + if (Profile.currentProfile() != null) { + Profile.currentProfile().getMappings().getActiveMapping().showFeedback(project, this); + } + + // WINDOW Settings + menuBarController.alwaysOnTopItem.setSelected(profilSettings.isWindowAlwaysOnTop()); + getStage().setAlwaysOnTop(profilSettings.isWindowAlwaysOnTop()); + + setTitle(); + showPage(pageNumber); + } + + @Override + public Project getProject() { + return project; + } + + public MidiHandler getMidiHandler() { + return midiHandler; + } + + public MainToolbarController getToolbarController() { + return toolbarController; + } + + // Plugins + /** + * Fügt ein MenuItem ins Menu hinzu + * + * @param item + * + * @since 2.0.0 + */ + public void addMenuItem(MenuItem item) { + menuBarController.extensionMenu.getItems().add(item); + if (!menuBarController.extensionMenu.isVisible()) { + menuBarController.extensionMenu.setVisible(true); + } + } + + public void setGridColor(Color gridColor) { + this.gridColor = gridColor; + try { + Field field = padGridPane.getClass().getDeclaredField("gridLines"); + field.setAccessible(true); + Group group = (Group) field.get(padGridPane); + if (group != null) { + for (Node node : group.getChildren()) { + if (node instanceof Line) { + ((Line) node).setStroke(gridColor); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/KeyboardMapperViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/KeyboardMapperViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..580f84d0f31c897f9b92d2262839ddf9c4a57fe3 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/KeyboardMapperViewController.java @@ -0,0 +1,86 @@ +package de.tobias.playpad.viewcontroller.mapper; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.mapper.KeyboardMapper; +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MapperViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.StringUtils; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.Scene; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.stage.Stage; + +public class KeyboardMapperViewController extends MapperViewController { + + @FXML private Label keyLabel; + @FXML private Button mappingButton; + + private KeyboardMapper mapper; + + public KeyboardMapperViewController() { + super("keyboard", "de/tobias/playpad/assets/view/mapper/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public Mapper getMapper() { + return mapper; + } + + @Override + public void hideFeedback() {} + + @Override + public void showFeedback() {} + + private void setLabel() { + keyLabel.setText(mapper.getReadableName()); + } + + @FXML + private void mappingButtonHandler(ActionEvent event) { + Alert alert = new Alert(AlertType.NONE); + alert.setTitle(Localization.getString(Strings.Mapper_Keyboard_Name)); + alert.setContentText(Localization.getString(Strings.Info_Mapper_PressKey)); + Scene scene = alert.getDialogPane().getScene(); + + scene.setOnKeyPressed(ev -> + { + mapper.setKey(ev.getCode().getName()); + mapper.setCode(ev.getCode()); + setLabel(); + }); + scene.setOnKeyReleased(ev -> + { + // Close on Finish (alert.close() does not work) + ((Stage) scene.getWindow()).close(); + }); + scene.setOnKeyTyped(ev -> + { + if (!StringUtils.isStringNotVisable(ev.getCharacter())) { + mapper.setKey(ev.getCharacter().toUpperCase()); + setLabel(); + } + }); + + alert.getButtonTypes().add(ButtonType.CANCEL); + alert.initOwner(getWindow()); + alert.showAndWait(); + } + + @Override + public void showInputMapperUI() { + mappingButton.fire(); + } + + public void setMapper(KeyboardMapper keyboardMapper) { + this.mapper = keyboardMapper; + setLabel(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/MidiMapperViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/MidiMapperViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..a24809d66ebaa5437f350ebd1dc746279eb53599 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/mapper/MidiMapperViewController.java @@ -0,0 +1,146 @@ +package de.tobias.playpad.viewcontroller.mapper; + +import javax.sound.midi.MidiMessage; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.feedback.DoubleSimpleFeedback; +import de.tobias.playpad.action.feedback.FeedbackType; +import de.tobias.playpad.action.feedback.SingleSimpleFeedback; +import de.tobias.playpad.action.mapper.Mapper; +import de.tobias.playpad.action.mapper.MapperViewController; +import de.tobias.playpad.action.mapper.MidiMapper; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.midi.MidiListener; +import de.tobias.playpad.viewcontroller.option.feedback.DoubleFeedbackViewController; +import de.tobias.playpad.viewcontroller.option.feedback.SingleFeedbackViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +public class MidiMapperViewController extends MapperViewController implements MidiListener { + + @FXML private Label midiInputKeyLabel; + @FXML private Button midiInputRecordButton; + + @FXML private VBox root; + + private MidiMapper mapper; + + private ContentViewController feedbackController; + + public MidiMapperViewController() { + super("midi", "de/tobias/playpad/assets/view/mapper/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public Mapper getMapper() { + return mapper; + } + + @Override + public void hideFeedback() { + if (feedbackController != null) { + root.getChildren().remove(feedbackController.getParent()); + } + } + + @Override + public void showFeedback() { + if (feedbackController != null) { + if (root.getChildren().contains(feedbackController.getParent())) + root.getChildren().remove(feedbackController.getParent()); + root.getChildren().add(feedbackController.getParent()); + VBox.setVgrow(feedbackController.getParent(), Priority.ALWAYS); + } + } + + /** + * Midi Listener von SettingsViewController, damit dieser wiederhergestellt werden kann am Ende. + */ + private MidiListener currentListener; + + /** + * Current Alert for mapping. + */ + private Alert alert; + + @FXML + private void midiInputRecordButtonHandler(ActionEvent event) { + currentListener = Midi.getInstance().getListener(); + Midi.getInstance().setListener(this); + + alert = new Alert(AlertType.NONE); + alert.setTitle(Localization.getString(Strings.Mapper_Midi_Name)); + alert.setContentText(Localization.getString(Strings.Info_Mapper_PressKey)); + alert.getButtonTypes().add(ButtonType.CANCEL); + alert.initOwner(getWindow()); + alert.showAndWait().ifPresent(result -> + { + if (result == ButtonType.CANCEL) { + Midi.getInstance().setListener(currentListener); + currentListener = null; + alert = null; + } + }); + } + + /** + * Record new Midi Key + */ + @Override + public void onMidiAction(MidiMessage message) { + Platform.runLater(() -> + { + if (alert != null) { + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.close(); + alert = null; + } + mapper.setCommand(message.getMessage()[0]); + mapper.setKey(message.getMessage()[1]); + + midiInputKeyLabel.setText(String.valueOf(mapper.getKey())); + }); + Midi.getInstance().setListener(currentListener); + currentListener = null; + } + + @Override + public void showInputMapperUI() { + midiInputRecordButton.fire(); + } + + public void setMapper(MidiMapper midiMapper) { + this.mapper = midiMapper; + + midiInputKeyLabel.setText(String.valueOf(mapper.getKey())); + + Midi.getInstance().getMidiDevice().ifPresent(device -> + { + if (device.supportFeedback()) { + // remove old Elements + if (feedbackController != null) { + root.getChildren().remove(feedbackController.getParent()); + } + // add new Elements + if (mapper.getFeedbackType() == FeedbackType.SINGLE) { + feedbackController = new SingleFeedbackViewController((SingleSimpleFeedback) mapper.getFeedback(), device.getColors()); + } else if (mapper.getFeedbackType() == FeedbackType.DOUBLE) { + feedbackController = new DoubleFeedbackViewController((DoubleSimpleFeedback) mapper.getFeedback(), device.getColors()); + } + showFeedback(); + } + }); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/AudioTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/AudioTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..5e0c3bd36672fa2d417d967a630e3163b1e928d5 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/AudioTabViewController.java @@ -0,0 +1,108 @@ +package de.tobias.playpad.viewcontroller.option; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.audio.AudioRegistry; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.AudioTypeViewController; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.Worker; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.AnchorPane; + +public class AudioTabViewController extends SettingsTabViewController { + + // Audio + @FXML private ComboBox<String> audioTypeComboBox; + @FXML private AnchorPane audioUserInfoSettings; + private AudioTypeViewController audioViewController; + private boolean changeAudioSettings; + + public AudioTabViewController(boolean playerActive) { + super("audioTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + + if (playerActive) { + audioTypeComboBox.setDisable(true); + audioUserInfoSettings.setDisable(true); + } + } + + @Override + public void init() { + ProfileSettings profileSettings = Profile.currentProfile().getProfileSettings(); + + // Audio + audioTypeComboBox.getItems().addAll(AudioRegistry.getAudioSystems().keySet()); + audioTypeComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + if (b != null && c != null) + changeAudioSettings = true; + showAudioSettings(c); + }); + showAudioSettings(profileSettings.getAudioClass()); + } + + private void showAudioSettings(String classID) { + if (audioViewController != null) { + if (audioViewController.isChanged()) { + changeAudioSettings = true; + } + } + + audioUserInfoSettings.getChildren().clear(); + + audioViewController = AudioRegistry.getAudioSystems().get(classID).getAudioViewController(); + if (audioViewController != null) { + audioUserInfoSettings.getChildren().add(audioViewController.getParent()); + } + } + + @Override + public void loadSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + audioTypeComboBox.getSelectionModel().select(profileSettings.getAudioClass()); + + } + + @Override + public void saveSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + profileSettings.setAudioClass(audioTypeComboBox.getValue()); + + } + + @Override + public boolean needReload() { + if (audioViewController != null) { + if (audioViewController.isChanged()) { + changeAudioSettings = true; + } + } + return changeAudioSettings; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + Worker.runLater(() -> + { + project.getPads().values().forEach(pad -> pad.loadContent()); + }); + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Audio_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/GeneralTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/GeneralTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..016a35a9570e0492ea51810a9994142e8048a5ab --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/GeneralTabViewController.java @@ -0,0 +1,257 @@ +package de.tobias.playpad.viewcontroller.option; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.NumberUtils; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.stage.DirectoryChooser; +import javafx.stage.Screen; + +public class GeneralTabViewController extends SettingsTabViewController { + + private static final String DIGIT_POSITIV = "^[1-9]\\d*$"; + + private Screen mainWindowScreen; + private ViewController parentController; // Für Benachrichtungen + + @FXML private TextField pageCountTextField; + @FXML private TextField columnTextField; + @FXML private TextField rowTextField; + + @FXML private CheckBox liveModeCheckBox; + + @FXML private TextField cacheTextField; + @FXML private Label cacheSizeLabel; + + private boolean changeSettings; + + public GeneralTabViewController(Screen screen, ViewController parentController, boolean activePlayer) { + super("generalTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + this.mainWindowScreen = screen; + this.parentController = parentController; + + if (activePlayer) { + rowTextField.setDisable(true); + columnTextField.setDisable(true); + pageCountTextField.setDisable(true); + } + calcCacheSize(); + } + + @Override + public void init() { + pageCountTextField.textProperty().addListener((a, b, c) -> + { + if (c.matches(DIGIT_POSITIV) && !c.isEmpty()) { + int number = Integer.valueOf(c); + if (number > ProfileSettings.MAX_PAGES) { + pageCountTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Zahl zu groß + } else { + pageCountTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); // Zahl ok + } + } else { + pageCountTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Negativ oder leer + } + }); + + columnTextField.textProperty().addListener((a, b, c) -> + { + if (c.matches(DIGIT_POSITIV) && !c.isEmpty()) { + if (screenValid()) { + columnTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); // Zahl ok + } else { + columnTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Zahl zu groß + } + } else { + columnTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Negativ oder leer + } + }); + + rowTextField.textProperty().addListener((a, b, c) -> + { + if (c.matches(DIGIT_POSITIV) && !c.isEmpty()) { + if (screenValid()) { + rowTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); // Zahl ok + } else { + rowTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Zahl zu groß + } + } else { + rowTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); // Negativ oder leer + } + }); + } + + @FXML + private void cacheChooseHandler(ActionEvent event) { + DirectoryChooser chooser = new DirectoryChooser(); + File folder = chooser.showDialog(getStage()); + if (folder != null) { + Path folderPath = folder.toPath(); + Profile.currentProfile().getProfileSettings().setCachePath(folderPath); + cacheTextField.setText(folderPath.toString()); + } + } + + @FXML + private void cacheResetButtonHandler(ActionEvent event) { + try { + int deleteFiles = 0; + for (Path path : Files.newDirectoryStream(ApplicationUtils.getApplication().getPath(PathType.CACHE))) { + if (Files.isRegularFile(path)) { + try { + Files.delete(path); + deleteFiles++; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + parentController.showInfoMessage(Localization.getString(Strings.Info_Settings_CacheDelete, deleteFiles), + PlayPadMain.stageIcon.get()); + + calcCacheSize(); + } catch (IOException e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Settings_CacheClear, e.getLocalizedMessage())); + } + } + + @FXML + private void resetDialogs(ActionEvent event) { + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + + profilSettings.setDialogDragAndDrop(true); + parentController.showInfoMessage(Localization.getString(Strings.Info_Settings_ResetWarning)); + } + + private void calcCacheSize() { + try { + double size = 0; + Path path = Profile.currentProfile().getProfileSettings().getCachePath(); + if (Files.notExists(path)) + Files.createDirectories(path); + + for (Path item : Files.newDirectoryStream(Profile.currentProfile().getProfileSettings().getCachePath())) { + size += Files.size(item); + } + cacheSizeLabel.setText(Localization.getString(Strings.UI_Window_Settings_Gen_CacheSize, NumberUtils.numberToString(size))); + } catch (IOException e) { + e.printStackTrace(); + parentController.showErrorMessage(Localization.getString(Strings.Error_Settings_CacheSize, e.getMessage()), PlayPadMain.stageIcon); + } + } + + private boolean screenValid() { + double width = mainWindowScreen.getVisualBounds().getMaxX() - mainWindowScreen.getVisualBounds().getMinX(); + double height = mainWindowScreen.getVisualBounds().getMaxY() - mainWindowScreen.getVisualBounds().getMinY(); + + GlobalLayout layout = Profile.currentProfile().currentLayout(); + + try { + double neededWidth = layout.getMinWidth(Integer.valueOf(columnTextField.getText())); + double neededHeight = layout.getMinHeight(Integer.valueOf(rowTextField.getText())) + 100; + + if (neededHeight <= height && neededWidth <= width) + return true; + } catch (NumberFormatException e) {} + return false; + } + + @Override + public void loadSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + pageCountTextField.setText(String.valueOf(profileSettings.getPageCount())); + columnTextField.setText(String.valueOf(profileSettings.getColumns())); + rowTextField.setText(String.valueOf(profileSettings.getRows())); + + liveModeCheckBox.setSelected(profileSettings.isLiveMode()); + cacheTextField.setText(profileSettings.getCachePath().toString()); + + if (screenValid()) { + columnTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + rowTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, false); + } else { + columnTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + rowTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, true); + } + } + + @Override + public void saveSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + int columns = Integer.valueOf(columnTextField.getText()); + int rows = Integer.valueOf(rowTextField.getText()); + int pageCount = Integer.valueOf(pageCountTextField.getText()); + + if (profileSettings.getColumns() != columns || profileSettings.getRows() != rows || profileSettings.getPageCount() != pageCount) + changeSettings = true; + else + changeSettings = false; + + // Copy Settings + profileSettings.setColumns(columns); + profileSettings.setRows(rows); + profileSettings.setPageCount(pageCount); + + profileSettings.setLiveMode(liveModeCheckBox.isSelected()); + profileSettings.setCachePath(Paths.get(cacheTextField.getText())); + } + + @Override + public boolean needReload() { + return changeSettings; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + controller.getToolbarController().createPageButtons(); + controller.createPadViews(); + controller.showPage(controller.getPage()); + } + + @Override + public boolean validSettings() { + if (screenValid()) { + return true; + } else { + double width = mainWindowScreen.getVisualBounds().getMaxX() - mainWindowScreen.getVisualBounds().getMinX(); + double height = mainWindowScreen.getVisualBounds().getMaxY() - mainWindowScreen.getVisualBounds().getMinY(); + + GlobalLayout globalLayout = Profile.currentProfile().currentLayout(); + + int maxCartsX = (int) (width / globalLayout.getPadWidth()); + int maxCartsY = (int) ((height - 100) / globalLayout.getPadHeight()); + parentController.showErrorMessage(Localization.getString(Strings.Error_Profile_SmallScreen, maxCartsX, maxCartsY), + PlayPadMain.stageIcon.orElse(null)); + return false; + } + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Gen_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/LayoutTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/LayoutTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..2077e4e715160998d32974c43b44289433442afc --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/LayoutTabViewController.java @@ -0,0 +1,89 @@ +package de.tobias.playpad.viewcontroller.option; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.GlobalLayout; +import de.tobias.playpad.layout.LayoutConnect; +import de.tobias.playpad.layout.LayoutRegistry; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.GlobalLayoutViewController; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.DisplayableCell; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.VBox; + +public class LayoutTabViewController extends SettingsTabViewController { + + @FXML private VBox layoutContainer; + @FXML private ComboBox<LayoutConnect> layoutTypeComboBox; + private GlobalLayoutViewController globalLayoutViewController; + + public LayoutTabViewController() { + super("layoutTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + + String layoutType = Profile.currentProfile().getProfileSettings().getLayoutType(); + layoutTypeComboBox.setValue(LayoutRegistry.getLayout(layoutType)); + } + + @Override + public void init() { + // Layout + layoutTypeComboBox.getItems().setAll(LayoutRegistry.getValues()); + layoutTypeComboBox.valueProperty().addListener((a, b, c) -> + { + String type = c.getType(); + + Profile.currentProfile().getProfileSettings().setLayoutType(type); + GlobalLayout layout = Profile.currentProfile().getLayout(type); + try { + setLayoutController(c.getGlobalLayoutViewController(layout)); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Layout_Load, e.getMessage())); + } + }); + + layoutTypeComboBox.setCellFactory((list) -> new DisplayableCell<>()); + layoutTypeComboBox.setButtonCell(new DisplayableCell<>()); + } + + private void setLayoutController(GlobalLayoutViewController globalLayoutViewController) { + if (this.globalLayoutViewController != null) + layoutContainer.getChildren().remove(this.globalLayoutViewController.getParent()); + + if (globalLayoutViewController != null) { + this.globalLayoutViewController = globalLayoutViewController; + layoutContainer.getChildren().add(globalLayoutViewController.getParent()); + } + } + + @Override + public void loadSettings(Profile profile) {} + + @Override + public void saveSettings(Profile profile) {} + + @Override + public boolean needReload() { + return true; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + controller.loadUserCss(); + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Layout_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/MappingTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MappingTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..c8130b66d3f74fa123462ea0ba340cf4a5afcb9f --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MappingTabViewController.java @@ -0,0 +1,169 @@ +package de.tobias.playpad.viewcontroller.option; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.Action; +import de.tobias.playpad.action.ActionConnect; +import de.tobias.playpad.action.ActionDisplayable; +import de.tobias.playpad.action.ActionRegistery; +import de.tobias.playpad.action.ActionType; +import de.tobias.playpad.action.Mapping; +import de.tobias.playpad.action.mapper.MapperRegistry; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.IMapperOverviewViewController; +import de.tobias.playpad.viewcontroller.IMappingTabViewController; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.DisplayableCell; +import de.tobias.playpad.viewcontroller.cell.DisplayableTreeCell; +import de.tobias.playpad.viewcontroller.dialog.MappingListViewController; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; +import javafx.scene.layout.VBox; + +public class MappingTabViewController extends SettingsTabViewController implements IMappingTabViewController { + + @FXML private ComboBox<Mapping> mappingComboBox; + @FXML private Button editMappingsButton; + + @FXML private TreeView<ActionDisplayable> treeView; + + @FXML private VBox detailView; + private IMapperOverviewViewController mapperOverviewViewController; + + private Mapping mapping; + + public MappingTabViewController() { + super("mapping", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public void init() { + mappingComboBox.setCellFactory(list -> new DisplayableCell<>()); + mappingComboBox.setButtonCell(new DisplayableCell<>()); + + mappingComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + mapping = c; + Profile.currentProfile().getMappings().setActiveMapping(c); + createTreeViewContent(); + }); + + treeView.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + detailView.getChildren().clear(); + + if (c != null) { + ContentViewController controller = c.getValue().getSettingsViewController(); + if (controller == null) { + controller = c.getValue().getActionSettingsViewController(mapping, this); + } + if (controller != null) { + detailView.getChildren().add(controller.getParent()); + } + if (c.getValue() instanceof Action) { + showMapperFor((Action) c.getValue()); + } + } + }); + treeView.setCellFactory(list -> new DisplayableTreeCell<>()); + } + + private TreeItem<ActionDisplayable> createTreeView(Mapping mapping) { + TreeItem<ActionDisplayable> rootItem = new TreeItem<>(); + Set<String> types = ActionRegistery.getTypes(); + List<String> sortedTypes = types.stream().sorted().collect(Collectors.toList()); + + // Sort the tpyes for the treeview + for (ActionType actionType : ActionType.values()) { + createTreeViewForActionType(mapping, rootItem, sortedTypes, actionType); + } + + return rootItem; + } + + private void createTreeViewForActionType(Mapping mapping, TreeItem<ActionDisplayable> rootItem, List<String> sortedTypes, ActionType type) { + for (String tpye : sortedTypes) { + List<Action> actions = mapping.getActionsOfType(tpye); + ActionConnect actionConnect = ActionRegistery.getActionConnect(tpye); + if (actionConnect.geActionType() == type) { + TreeItem<ActionDisplayable> item = actionConnect.getTreeViewForActions(actions, mapping); + rootItem.getChildren().add(item); + } + } + } + + @FXML + private void editMappingsHandler(ActionEvent event) { + MappingListViewController controller = new MappingListViewController(Profile.currentProfile().getMappings(), getWindow()); + controller.getStage().showAndWait(); + setMappingItemsToList(); + } + + private void createTreeViewContent() { + TreeItem<ActionDisplayable> rootItem = createTreeView(mapping); + treeView.setRoot(rootItem); + } + + private void setMappingItemsToList() { + mappingComboBox.getItems().setAll(Profile.currentProfile().getMappings()); + mappingComboBox.setValue(Profile.currentProfile().getMappings().getActiveMapping()); + + mapping = mappingComboBox.getValue(); + } + + @Override + public void showMapperFor(Action action) { + try { + if (action != null) { + mapperOverviewViewController = MapperRegistry.getOverviewViewControllerInstance(); + mapperOverviewViewController.showAction(action, detailView); + } else { + detailView.getChildren().remove(mapperOverviewViewController.getParent()); + } + } catch (Exception e) {} + } + + // Tab Utils + @Override + public void loadSettings(Profile profile) { + setMappingItemsToList(); + createTreeViewContent(); + } + + @Override + public void saveSettings(Profile profile) {} + + @Override + public boolean needReload() { + return true; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + Profile.currentProfile().getMappings().getActiveMapping().clearFeedback(); + Profile.currentProfile().getMappings().getActiveMapping().showFeedback(project, controller); + Profile.currentProfile().getMappings().getActiveMapping().initFeedback(); + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Mapping_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..0c6e45c2e1c371685cd8d0ba349f51a78f3eaddb --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController.java @@ -0,0 +1,124 @@ +package de.tobias.playpad.viewcontroller.option; + +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.MidiUnavailableException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.AnchorPane; + +public class MidiTabViewController extends SettingsTabViewController { + + @FXML private AnchorPane rootPane; + + @FXML private CheckBox midiActiveCheckBox; + @FXML private ComboBox<String> deviceComboBox; + + public MidiTabViewController() { + super("midiTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + + Info[] data = Midi.getMidiDevices(); + // Gerät anzeigen - Doppelte weg + for (Info item : data) { + if (!deviceComboBox.getItems().contains(item.getName())) { + deviceComboBox.getItems().add(item.getName()); + + // aktives Gerät wählen + if (item.getName().equals(Profile.currentProfile().getProfileSettings().getMidiDevice())) { + deviceComboBox.getSelectionModel().select(item.getName()); + } + } + } + + } + + @Override + public void init() { + midiActiveCheckBox.selectedProperty().addListener((a, b, c) -> + { + deviceComboBox.setDisable(!c); + }); + } + + // Midi Device und Presets Choose + @FXML + private void deviceHandler(ActionEvent event) { + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + String device = deviceComboBox.getValue(); + + // Ändern und Speichern + if (device != null) { + if (isMidiActive()) { + Midi midi = Midi.getInstance(); + if (!device.equals(profilSettings.getMidiDevice()) || !midi.isOpen()) { + try { + // Setup + midi.lookupMidiDevice(device); + profilSettings.setMidiDeviceName(device); + + // UI Rückmeldung + if (midi.getInputDevice().isPresent()) { + showInfoMessage(Localization.getString(Strings.Info_Midi_Device_Connected, device)); + } + } catch (NullPointerException e) { + showErrorMessage(Localization.getString(Strings.Error_Midi_Device_Unavailible, device)); + e.printStackTrace(); + } catch (IllegalArgumentException | MidiUnavailableException e) { + showErrorMessage(Localization.getString(Strings.Error_Midi_Device_Busy, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + } + } + } + + public boolean isMidiActive() { + return midiActiveCheckBox.isSelected(); + } + + @Override + public void loadSettings(Profile profile) { + midiActiveCheckBox.setSelected(profile.getProfileSettings().isMidiActive()); + deviceComboBox.setDisable(!profile.getProfileSettings().isMidiActive()); + deviceComboBox.setValue(profile.getProfileSettings().getMidiDevice()); + } + + @Override + public void saveSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + // Midi + profileSettings.setMidiActive(isMidiActive()); + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public boolean needReload() { + return true; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Midi_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController2.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController2.java new file mode 100644 index 0000000000000000000000000000000000000000..796c012dc814fa5a745fe6f489cb296f114838d7 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/MidiTabViewController2.java @@ -0,0 +1,641 @@ +package de.tobias.playpad.viewcontroller.option; + +import java.util.Collections; +import java.util.Optional; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiUnavailableException; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.midi.MidiListener; +import de.tobias.playpad.model.Project; +import de.tobias.playpad.model.midi.Displayable; +import de.tobias.playpad.model.midi.MidiAction; +import de.tobias.playpad.model.midi.SubAction; +import de.tobias.playpad.model.midi.type.MidiKeyActionType; +import de.tobias.playpad.model.midi.type.MidiKeyActionTypes; +import de.tobias.playpad.model.midi.type.MidiKeyActionTypes.MidiKeyActionTypeStore; +import de.tobias.playpad.plugin.viewcontroller.IMainViewController; +import de.tobias.playpad.plugin.viewcontroller.IMidiTabViewController; +import de.tobias.playpad.plugin.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.settings.MidiPreset; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.PresetsViewController; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.ui.scene.NotificationPane; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.Parent; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class MidiTabViewController2 extends SettingsTabViewController + implements IMidiTabViewController, MidiListener, NotificationHandler, ChangeListener<TreeItem<Displayable>> { + + @FXML private AnchorPane rootPane; + private NotificationPane notificationPane; + + @FXML private CheckBox midiActiveCheckBox; + @FXML private ComboBox<String> deviceComboBox; + + @FXML private ComboBox<MidiPreset> presetsList; + @FXML private Button presetsEditButton; + @FXML private Button activateButton; + + @FXML private Button addMidiButton; + @FXML private Button addMidiDraftButton; + @FXML private Button draftButton; + @FXML private Button deleteMidiButton; + @FXML private Button clearMidiButton; + + @FXML private TreeView<Displayable> contentTreeView; + @FXML private ComboBox<MidiKeyActionTypeStore> midiActionTypeComboBox; + @FXML private AnchorPane settingsAnchorPane; + + // Midi Record + private boolean recordMidi; + private boolean useDraft; + private org.controlsfx.control.action.Action midiRecordCancelAction; + + private final Window owner; + + public MidiTabViewController2(Window owner) { + super("midiTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + this.owner = owner; + + owner.setOnShown(event -> + { + if (!Midi.getInstance().isOpen() && Profile.currentProfile().getProfileSettings().isMidiActive()) { + showError(Localization.getString(Strings.Info_Settings_Midi_NoDevice)); + } + updateButtonDisable(); + if (!Profile.currentProfile().getMidiSetting().getDraftAction().isPresent()) { + addMidiDraftButton.setDisable(true); + } + }); + + // Midi Listener auf Einstellungen + Midi.getInstance().setListener(this); + } + + @Override + public void init() { + // Notifiation Pane + midiRecordCancelAction = new org.controlsfx.control.action.Action(Localization.getString(Strings.Actions_Midi_Cancel), event -> + { + recordMidi = false; + notificationPane.hide(); + }); + + notificationPane = new NotificationPane(rootPane); + notificationPane.getStyleClass().add(NotificationPane.STYLE_CLASS_DARK); + + presetsList.valueProperty().addListener((a, b, c) -> + { + if (c != null) { + Collections.sort(c.getMidiActions()); // sortieren + + // Aktivieren Button ein und aus schalten + if (c.isActive()) { + activateButton.setDisable(true); + } else { + activateButton.setDisable(false); + } + + // items in treeview + showMidiPresetActions(); + } + }); + + // setup persets and select active or first + presetsList.setItems(Profile.currentProfile().getMidiSetting().getPresets()); + presetsList.getSelectionModel().select(0); // Standart Selectend + + for (MidiPreset preset : Profile.currentProfile().getMidiSetting().getPresets()) { // Preset Auswählen + if (preset.isActive()) { + presetsList.getSelectionModel().select(preset); // Wenn aktiv dann selecten + break; + } + } + + // Auswahlliste Links Setup + showMidiPresetActions(); + contentTreeView.setShowRoot(false); + contentTreeView.getSelectionModel().selectedItemProperty().addListener(this); + + // Action Types Init + midiActionTypeComboBox.getItems().setAll(MidiKeyActionTypes.getActions()); + + // ActionType Changed + midiActionTypeComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, c) -> + { + if (c != null) { + try { + MidiKeyActionType type = c.getActionType().newInstance(); + Optional<MidiAction> midiAction = getSelectedMidiAction(); + if (midiAction.isPresent()) { + if (!MidiKeyActionType.equals(type, midiAction.get().getActionType())) { + Device device = Midi.getInstance().getMidiDevice().get(); + + midiAction.get().setActionType(type, device.getDefaultColor(type.getClass())); + + updateChildrenOfRootItem(midiAction.get(), getTreeObject(midiAction.get(), contentTreeView.getRoot())); + showSettingsView(midiAction.get()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + deviceComboBox.setPlaceholder(new Label(Localization.getString(Strings.UI_Placeholder_MidiDevice))); + + Info[] data = Midi.getMidiDevices(); + // Gerät anzeigen - Doppelte weg + for (Info item : data) { + if (!deviceComboBox.getItems().contains(item.getName())) { + deviceComboBox.getItems().add(item.getName()); + + // aktives Gerät wählen + if (item.getName().equals(Profile.currentProfile().getProfileSettings().getMidiDevice())) { + deviceComboBox.getSelectionModel().select(item.getName()); + } + } + } + } + + @Override + public Parent getParent() { + return notificationPane; + } + + // UI Helper Getter und Setter + private void showMidiPresetActions() { + contentTreeView.setRoot(createMidiActionsTree(getSelectedPreset())); + } + + public void updateChildrenOfRootItem(MidiAction midiAction) { + updateChildrenOfRootItem(midiAction, getTreeObject(midiAction, contentTreeView.getRoot())); + } + + public void updateChildrenOfRootItem(MidiAction midiAction, TreeItem<Displayable> root) { + root.getChildren().clear(); + if (!midiAction.getActions().isEmpty() && midiAction.getActionType().showSubActions()) { + for (SubAction action : midiAction.getActions()) { + TreeItem<Displayable> treeItemAction = new TreeItem<>(action); + root.getChildren().add(treeItemAction); + } + } + root.setExpanded(true); + } + + private void addMidiActionToTree(MidiAction midiAction) { + TreeItem<Displayable> treeItemMidi = new TreeItem<>(midiAction); + int index = getSelectedPreset().getMidiActions().indexOf(midiAction); + + contentTreeView.getRoot().getChildren().add(index, treeItemMidi); + createMidiActionsTree(getSelectedPreset()); + selectMidiAction(midiAction); + } + + private void updateButtonDisable() { + Optional<Displayable> displayable = getSelectedAction(); + if (displayable.isPresent()) { + if (displayable.get() instanceof MidiAction) { // Root Node -> MidiAction + deleteMidiButton.setDisable(false); + draftButton.setDisable(false); + } else { + deleteMidiButton.setDisable(true); + draftButton.setDisable(true); + } + midiActionTypeComboBox.setDisable(false); + } else { + deleteMidiButton.setDisable(true); + draftButton.setDisable(true); + midiActionTypeComboBox.setDisable(true); + } + } + + private MidiPreset getSelectedPreset() { + return presetsList.getSelectionModel().getSelectedItem(); + } + + public Optional<MidiAction> getSelectedMidiAction() { + TreeItem<Displayable> item = contentTreeView.getSelectionModel().getSelectedItem(); + if (item != null) { + if (item.getValue() instanceof MidiAction) { + return Optional.of((MidiAction) item.getValue()); + } else { + return Optional.of((MidiAction) item.getParent().getValue()); + } + } else { + return Optional.empty(); + } + } + + public Optional<Displayable> getSelectedAction() { + TreeItem<Displayable> item = contentTreeView.getSelectionModel().getSelectedItem(); + if (item != null) { + return Optional.of(item.getValue()); + } else { + return Optional.empty(); + } + } + + public TreeItem<Displayable> getTreeObject(Displayable object, TreeItem<Displayable> root) { + if (root.getValue() == object) { + return root; + } else { + for (TreeItem<Displayable> child : root.getChildren()) { + TreeItem<Displayable> result = getTreeObject(object, child); + if (result != null) { + return result; + } + } + } + return null; + } + + private void selectMidiKeyActionType(MidiKeyActionType type) { + MidiKeyActionTypeStore store = MidiKeyActionTypes.getStoreForType(type); + midiActionTypeComboBox.setValue(store); + } + + // Show Methods + private TreeItem<Displayable> createMidiActionsTree(MidiPreset preset) { + TreeItem<Displayable> treeItemRoot = new TreeItem<>(); + + if (preset != null) { + for (MidiAction midiAction : preset.getMidiActions()) { + TreeItem<Displayable> treeItemMidi = new TreeItem<>(midiAction); + if (!midiAction.getActions().isEmpty() && midiAction.getActionType().showSubActions()) { + for (SubAction action : midiAction.getActions()) { + TreeItem<Displayable> treeItemAction = new TreeItem<>(action); + treeItemMidi.getChildren().add(treeItemAction); + } + } + treeItemRoot.getChildren().add(treeItemMidi); + } + } + + return treeItemRoot; + } + + private void selectPressedMidiAction(MidiMessage message) { + getSelectedPreset().getMidiActionForMidi(message).ifPresent(item -> Platform.runLater(() -> selectMidiAction(item))); + } + + private void selectMidiAction(MidiAction midiAction) { + // select item + TreeItem<Displayable> treeItem = getTreeObject(midiAction, contentTreeView.getRoot()); + contentTreeView.getSelectionModel().select(treeItem); + + // scroll to index (only index) + int index = contentTreeView.getSelectionModel().getSelectedIndex(); + contentTreeView.scrollTo(index); + } + + /** + * + * @param value + * MidiAction or SubAction + */ + public void showSettingsView(Displayable value) { + settingsAnchorPane.getChildren().clear(); + midiActionTypeComboBox.setValue(null); + + ContentViewController controller = null; + if (value != null) { + if (value instanceof MidiAction) { + MidiAction midiAction = (MidiAction) value; + MidiKeyActionType type = midiAction.getActionType(); + controller = type.getMainViewController(midiAction, this, this); + selectMidiKeyActionType(midiAction.getActionType()); + + } else if (value instanceof SubAction) { + SubAction action = (SubAction) value; + MidiAction midiAction = action.getMidiAction(); + + MidiKeyActionType type = midiAction.getActionType(); + controller = type.getSubViewController(action, this, this); + selectMidiKeyActionType(midiAction.getActionType()); + } + } + + // TODO Overhead mit neuen VC fixen, Reuable machen + if (controller != null) { + ViewController.setAnchor(controller.getParent(), 14, 0, 14, 0); + settingsAnchorPane.getChildren().add(controller.getParent()); + } + } + + // Midi Device und Presets Choose + @FXML + private void deviceHandler(ActionEvent event) { + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + String device = deviceComboBox.getValue(); + + // Ändern und Speichern + if (device != null) { + if (isMidiActive()) { + Midi midi = Midi.getInstance(); + if (!device.equals(profilSettings.getMidiDevice()) || !midi.isOpen()) { + try { + // Setup + midi.lookupMidiDevice(device); + profilSettings.setMidiDeviceName(device); + + // UI Rückmeldung + if (midi.getInputDevice().isPresent()) { + notify(Localization.getString(Strings.Info_Midi_Device_Connected, device), + PlayPadMain.notificationDisplayTimeMillis); + // mainPane.setDisable(false); BUG Disable / Enable der GUI wenn kein MIDI da ist + } + } catch (NullPointerException e) { + showError(Localization.getString(Strings.Error_Midi_Device_Unavailible, device)); + e.printStackTrace(); + } catch (IllegalArgumentException | MidiUnavailableException e) { + showError(Localization.getString(Strings.Error_Midi_Device_Busy, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + } + } + } + + @FXML + private void presetsEditButtonHandler(ActionEvent event) { + PresetsViewController controller = new PresetsViewController(owner); + controller.getStage().showAndWait(); + } + + @FXML + private void activateButtonHandler(ActionEvent event) { + MidiPreset item = presetsList.getSelectionModel().getSelectedItem(); + item.setActive(true); + activateButton.setDisable(true); + PresetsViewController.disableInvalidPresets(true, item, Profile.currentProfile().getMidiSetting()); + } + + // MidiActionHandlers + @FXML + private void addMidiButtonHandler(ActionEvent event) { + notificationPane.show(Localization.getString(Strings.Info_Midi_Record_Start), null, midiRecordCancelAction); + recordMidi = true; + useDraft = false; + } + + @FXML + private void addMidiDraftButtonHandler(ActionEvent event) { + notificationPane.show(Localization.getString(Strings.Info_Midi_Record_Start), null, midiRecordCancelAction); + recordMidi = true; + useDraft = true; + } + + @FXML + private void draftButtonHandler(ActionEvent event) { + Optional<MidiAction> midiAction = getSelectedMidiAction(); + if (midiAction.isPresent()) { + try { + Profile.currentProfile().getMidiSetting().setDraftAction(midiAction.get().clone()); + addMidiDraftButton.setDisable(false); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + showError(Localization.getString(Strings.Error_Standard_Gen, e.getLocalizedMessage())); + } + } + } + + @FXML + private void deleteMidiButtonHandler(ActionEvent event) { + Optional<MidiAction> midiAction = getSelectedMidiAction(); + if (midiAction.isPresent()) { + getSelectedPreset().removeAction(midiAction.get()); // Model + + // Remove from Tree UI + TreeItem<Displayable> midiTreeItem = getTreeObject(midiAction.get(), contentTreeView.getRoot()); + contentTreeView.getRoot().getChildren().remove(midiTreeItem); + } + } + + @FXML + private void clearMidiButtonHandler(ActionEvent event) { + Alert alert = new Alert(AlertType.CONFIRMATION); + + alert.initOwner(owner); + alert.initModality(Modality.WINDOW_MODAL); + Stage dialog = (Stage) alert.getDialogPane().getScene().getWindow(); + PlayPadMain.stageIcon.ifPresent(dialog.getIcons()::add); + + alert.setContentText(Localization.getString(Strings.Info_Settings_Midi_ClearPreset)); + alert.showAndWait().filter(item -> item == ButtonType.OK).ifPresent(item -> + { + getSelectedPreset().clearActions(); + showMidiPresetActions(); + }); + } + + // Accessor for User Input + public boolean isMidiActive() { + return midiActiveCheckBox.isSelected(); + } + + // Midi + @Override + public void onMidiAction(MidiMessage message) { + if (message.getLength() >= 3) { + if (message.getMessage()[2] != 0) { + // Neuer Midi Key (RECORD) + if (recordMidi) { + recordMidi = false; + notificationPane.hide(); + + int midiCommand = message.getMessage()[0]; + byte midiKey = message.getMessage()[1]; + + if (getSelectedPreset().isContaining(midiCommand, midiKey)) { + notify(Localization.getString(Strings.Error_Midi_Record_Fail), PlayPadMain.notificationDisplayTimeMillis); + return; + } + + try { + final MidiAction midiAction; + + // Neue Aktion + if (useDraft == false) { + midiAction = new MidiAction(midiCommand, midiKey, getSelectedPreset()); + if (midiAction != null) { + Platform.runLater(() -> + { + // Model neue Midi Action + getSelectedPreset().addAction(midiAction); + Collections.sort(getSelectedPreset().getMidiActions()); + + // GUI hinzufügen + addMidiActionToTree(midiAction); + selectPressedMidiAction(message); + }); + } + } else { + // Verwende Vorlage und passe Midi an + midiAction = Profile.currentProfile().getMidiSetting().getDraftAction().get().clone(); + midiAction.setMidiPreset(getSelectedPreset()); + midiAction.setMidiCommand(midiCommand); + midiAction.setMidiKey(midiKey); + + // Cart ID ändern + Platform.runLater(() -> + { + if (midiAction.getActionType().handleClone(midiAction, this)) { + if (midiAction != null) { + // Model neue Midi Action + getSelectedPreset().addAction(midiAction); + Collections.sort(getSelectedPreset().getMidiActions()); + + // GUI hinzufügen + addMidiActionToTree(midiAction); + selectPressedMidiAction(message); + } + } + }); + } + } catch (Exception e) { + showError(Localization.getString(Strings.Error_Standard_Gen, e.getLocalizedMessage())); + e.printStackTrace(); + } + } else { + selectPressedMidiAction(message); + } + } + } + } + + // NotificationHandler + @Override + public void notify(String text, long duration) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration)); + } + } + + @Override + public void notify(String text, long duration, Runnable finish) { + if (Platform.isFxApplicationThread()) { + notificationPane.showAndHide(text, duration, finish); + } else { + Platform.runLater(() -> notificationPane.showAndHide(text, duration, finish)); + } + } + + @Override + public void show(String message, org.controlsfx.control.action.Action... action) { + if (Platform.isFxApplicationThread()) { + notificationPane.show(message, null, action); + } else { + Platform.runLater(() -> notificationPane.show(message, null, action)); + } + } + + @Override + public void showError(String message) { + if (Platform.isFxApplicationThread()) { + notificationPane.showError(message); + } else { + Platform.runLater(() -> notificationPane.showError(message)); + } + } + + @Override + public void hide() { + if (Platform.isFxApplicationThread()) { + notificationPane.hide(); + } else { + Platform.runLater(() -> notificationPane.hide()); + } + } + + // Update Data (Wird in SettingsViewController bei showCurrentSettings aufgerufen) + @Override + public void updateData() { + ProfileSettings profileSettings = Profile.currentProfile().getProfileSettings(); + deviceComboBox.setValue(profileSettings.getMidiDevice()); + midiActiveCheckBox.setSelected(profileSettings.isMidiActive()); + } + + // Display Settings ViewController der jeweiligen Action, basierend auf dem Type + /* + * Wird aufgerufen, wenn in der Liste Links was ausgewählt wird + */ + @Override + public void changed(ObservableValue<? extends TreeItem<Displayable>> observable, TreeItem<Displayable> oldValue, + TreeItem<Displayable> newValue) { + settingsAnchorPane.getChildren().clear(); + if (newValue != null) + showSettingsView(newValue.getValue()); + updateButtonDisable(); + } + + @Override + public void loadSettings(Profile profile) { + updateData(); + } + + @Override + public void saveSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + // Midi + profileSettings.setMidiActive(isMidiActive()); + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public boolean needReload() { + return true; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) { + if (Midi.getInstance().getMidiDevice().isPresent()) + try { + Midi.getInstance().getMidiDevice().get().showFeedbackForPage(controller.getPage(), controller.getPage(), project); + } catch (MidiUnavailableException | InvalidMidiDataException e) { + e.printStackTrace(); + } + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Midi_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/PlayerTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/PlayerTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..94713e8a15dba9fae93ac619173bdf5eebfd416a --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/PlayerTabViewController.java @@ -0,0 +1,83 @@ +package de.tobias.playpad.viewcontroller.option; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.TimeMode; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.EnumCell; +import de.tobias.playpad.viewcontroller.main.IMainViewController; +import de.tobias.playpad.viewcontroller.settings.FadeViewController; +import de.tobias.playpad.viewcontroller.settings.WarningFeedbackViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.VBox; + +public class PlayerTabViewController extends SettingsTabViewController { + + // Player + @FXML private VBox warningFeedbackContainer; + @FXML private VBox fadeContainer; + @FXML private ComboBox<TimeMode> timeDisplayComboBox; + + public PlayerTabViewController() { + super("playerTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + + // Player + FadeViewController fadeViewController = new FadeViewController(); + fadeViewController.setFade(Profile.currentProfile().getProfileSettings().getFade()); + fadeContainer.getChildren().add(fadeViewController.getParent()); + setAnchor(fadeViewController.getParent(), 0, 0, 0, 0); + } + + public ComboBox<TimeMode> getTimeDisplayComboBox() { + return timeDisplayComboBox; + } + + @Override + public void init() { + WarningFeedbackViewController controller = new WarningFeedbackViewController(); + warningFeedbackContainer.getChildren().add(controller.getParent()); + + // Player + timeDisplayComboBox.getItems().addAll(TimeMode.values()); + timeDisplayComboBox.setButtonCell(new EnumCell<>(Strings.Pad_TimeMode_BaseName)); + timeDisplayComboBox.setCellFactory(list -> new EnumCell<>(Strings.Pad_TimeMode_BaseName)); + } + + @Override + public void loadSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + timeDisplayComboBox.setValue(profileSettings.getPlayerTimeDisplayMode()); + } + + @Override + public void saveSettings(Profile profile) { + ProfileSettings profileSettings = profile.getProfileSettings(); + + // Player + profileSettings.setPlayerTimeDisplayMode(timeDisplayComboBox.getValue()); + } + + @Override + public boolean needReload() { + return false; + } + + @Override + public void reload(Profile profile, Project project, IMainViewController controller) {} + + @Override + public boolean validSettings() { + return true; + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Player_Title); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/SettingsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/SettingsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..2e4726e0816543c7489c1b544ec5fdf32bccf8c9 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/SettingsViewController.java @@ -0,0 +1,169 @@ +package de.tobias.playpad.viewcontroller.option; + +import java.util.ArrayList; +import java.util.List; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.Strings; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.ISettingsViewController; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.stage.Screen; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class SettingsViewController extends ViewController implements ISettingsViewController { + + @FXML private TabPane tabPane; + @FXML private Button finishButton; + + protected List<SettingsTabViewController> tabs = new ArrayList<>(); + + public SettingsViewController(Midi midiHandler, Screen screen, Window owner, Project project) { + super("settingsView", "de/tobias/playpad/assets/view/option/", null, PlayPadMain.getUiResourceBundle()); + + boolean activePlayer = project.getPlayedPlayers() > 0; + + addTab(new GeneralTabViewController(screen, this, activePlayer)); + addTab(new MappingTabViewController()); + addTab(new MidiTabViewController()); + addTab(new LayoutTabViewController()); + addTab(new PlayerTabViewController()); + + // Content Types + for (String type : PadContentRegistry.getTypes()) { + try { + SettingsTabViewController controller = PadContentRegistry.getPadContentConnect(type).getSettingsTabViewController(activePlayer); + if (controller != null) { + addTab(controller); + } + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + + // Listener + PlayPadPlugin.getImplementation().getSettingsViewListener().forEach(l -> + { + try { + l.onInit(this); + } catch (Exception e) { + e.printStackTrace(); + } + }); + addTab(new UpdateTabViewController()); + + getStage().initOwner(owner); + + // Show Current Settings + showCurrentSettings(); + } + + @Override + public void init() { + // KeyCode + addCloseKeyShortcut(() -> finishButton.fire()); + finishButton.defaultButtonProperty().bind(finishButton.focusedProperty()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(715); + stage.setMinHeight(700); + stage.setTitle(Localization.getString(Strings.UI_Window_Settings_Title, Profile.currentProfile().getRef().getName())); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + // Copy Of Settings + public boolean closeRequest() { + boolean valid = true; + for (SettingsTabViewController controller : tabs) { + if (controller.validSettings() == false) { + valid = false; + } + } + + if (valid) { // Einstellungen sind Valide + // Listener + PlayPadPlugin.getImplementation().getSettingsViewListener().forEach(l -> l.onClose(this)); + + saveChanges(); + getStage().close(); + updateData(); + return true; + } else { + return false; + } + } + + // Settings aus AppSettings + private void showCurrentSettings() { + Profile profile = Profile.currentProfile(); + for (SettingsTabViewController controller : tabs) { + controller.loadSettings(profile); + } + } + + private void saveChanges() { + Profile profile = Profile.currentProfile(); + for (SettingsTabViewController controller : tabs) { + controller.saveSettings(profile); + } + + try { + profile.save(); + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Profile_Save, e.getLocalizedMessage())); + e.printStackTrace(); + } + } + + public boolean needUpdate() { + boolean change = false; + for (SettingsTabViewController controller : tabs) { + if (controller.needReload()) { + change = true; + } + } + return change; + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + boolean valid = true; + for (SettingsTabViewController controller : tabs) { + if (controller.validSettings() == false) { + valid = false; + } + } + + if (valid) { // Einstellungen sind Valide + // Listener + PlayPadPlugin.getImplementation().getSettingsViewListener().forEach(l -> l.onClose(this)); + + saveChanges(); + getStage().close(); + updateData(); + } + } + + public void addTab(SettingsTabViewController controller) { + tabs.add(controller); + tabPane.getTabs().add(new Tab(controller.name(), controller.getParent())); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/UpdateTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/UpdateTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..0edd9042f39d8a1917d7f57927b18b23d6793074 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/UpdateTabViewController.java @@ -0,0 +1,260 @@ +package de.tobias.playpad.viewcontroller.option; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +import de.tobias.playpad.AppUserInfoStrings; +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.Strings; +import de.tobias.playpad.Updatable; +import de.tobias.playpad.UpdateRegistery; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.SettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.UpdateCell; +import de.tobias.playpad.viewcontroller.dialog.UpdaterDialog; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.application.NativeLauncher; +import de.tobias.utils.application.container.PathType; +import de.tobias.utils.util.Localization; +import de.tobias.utils.util.OS; +import de.tobias.utils.util.OS.OSType; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.image.Image; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class UpdateTabViewController extends SettingsTabViewController { + + private static final String DOWNLOAD_FOLDER = "Updates"; + private static final String UPDATER_JAR = "Updater.jar"; + private static final String UPDATER_EXE = "Updater.exe"; + + @FXML private Label currentVersionLabel; + @FXML private Label newVersionLabel; + + @FXML private CheckBox automaticSearchCheckBox; + @FXML private Button manualSearchButton; + + @FXML private ListView<Updatable> openUpdateList; + @FXML private Button updateButton; + + private ProgressIndicator progressIndecator; + private Label placeholderLabel; + + public UpdateTabViewController() { + super("updateTab", "de/tobias/playpad/assets/view/option/", PlayPadMain.getUiResourceBundle()); + + openUpdateList.getItems().setAll(UpdateRegistery.getAvailableUpdates()); + updateButton.setDisable(openUpdateList.getItems().isEmpty()); + + Worker.runLater(() -> + { + Updatable updater = PlayPadMain.getUpdater(); + updater.checkUpdate(); + Platform.runLater(() -> + { + currentVersionLabel.setText(Localization.getString(Strings.UI_Window_Settings_Updates_CurrentVersion, + updater.getCurrentVersion(), updater.getCurrentBuild())); + newVersionLabel.setText(Localization.getString(Strings.UI_Window_Settings_Updates_CurrentVersion, updater.getNewVersion(), + updater.getNewBuild())); + }); + }); + } + + @Override + public void init() { + openUpdateList.setCellFactory(list -> new UpdateCell()); + + progressIndecator = new ProgressIndicator(-1); + progressIndecator.setMinSize(25, 25); + + placeholderLabel = new Label(Localization.getString(Strings.UI_Placeholder_Updates)); + openUpdateList.setPlaceholder(placeholderLabel); + + updateButton.setDisable(openUpdateList.getItems().isEmpty()); + } + + @FXML + private void manualSearchHandler(ActionEvent event) { + openUpdateList.getItems().clear(); + + openUpdateList.setPlaceholder(progressIndecator); + UpdateRegistery.lookupUpdates(); + openUpdateList.setPlaceholder(placeholderLabel); + + openUpdateList.getItems().setAll(UpdateRegistery.getAvailableUpdates()); + updateButton.setDisable(openUpdateList.getItems().isEmpty()); + } + + @FXML + private void updateHandler(ActionEvent event) { + update(getStage()); + } + + public static void update(Window dialogOwner) { + String parameter = UpdateRegistery + .buildParamaterString(ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, DOWNLOAD_FOLDER).toString()); + if (OS.getType() == OSType.Windows) { + try { + Path fileJar = Paths.get(UPDATER_JAR); + Path fileExe = Paths.get(UPDATER_EXE); + Path fileJarFolder = ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, UPDATER_JAR); + Path fileExeFolder = ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, UPDATER_EXE); + + if (Files.exists(fileJar)) { + startJarFile(parameter, fileJar); + } else if (Files.exists(fileExe)) { + startExeFile(parameter, fileExe); + + } else if (Files.exists(fileJarFolder)) { + startJarFile(parameter, fileJarFolder); + } else if (Files.exists(fileExeFolder)) { + startExeFile(parameter, fileExeFolder); + } else { + UpdaterDialog dialog = new UpdaterDialog(dialogOwner); + dialog.show(); + + Worker.runLater(() -> + { + String updaterURL = ApplicationUtils.getApplication().getInfo().getUserInfo().get(AppUserInfoStrings.UPDATER_PROGRAM) + + UPDATER_EXE; + Path path = ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, UPDATER_EXE); + try { + downloadUpdater(updaterURL, path); + startExeFile(parameter, path); + } catch (Exception e) { + e.printStackTrace(); + String errorMessage = Localization.getString(Strings.Error_Update_Download, e.getMessage()); + showErrorMessage(errorMessage, PlayPadPlugin.getImplementation().getIcon(), dialogOwner); + } + }); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + try { + Path fileJar = Paths.get(UPDATER_JAR); + Path fileJarFolder = ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, UPDATER_JAR); + + if (Files.exists(fileJar)) { + startJarFile(parameter, fileJar); + } else if (Files.exists(fileJarFolder)) { + startJarFile(parameter, fileJarFolder); + } else { + UpdaterDialog dialog = new UpdaterDialog(dialogOwner); + dialog.show(); + + Worker.runLater(() -> + { + String updaterURL = ApplicationUtils.getApplication().getInfo().getUserInfo().get(AppUserInfoStrings.UPDATER_PROGRAM) + + UPDATER_JAR; + Path path = ApplicationUtils.getApplication().getPath(PathType.DOWNLOAD, UPDATER_JAR); + try { + downloadUpdater(updaterURL, path); + startJarFile(parameter, path); + } catch (Exception e) { + e.printStackTrace(); + String errorMessage = Localization.getString(Strings.Error_Update_Download, e.getMessage()); + showErrorMessage(errorMessage, PlayPadPlugin.getImplementation().getIcon(), dialogOwner); + } + }); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private static void downloadUpdater(String updaterURL, Path path) throws IOException, MalformedURLException { + if (Files.notExists(path)) { + Files.createDirectories(path.getParent()); + Files.createFile(path); + } + + URLConnection conn = new URL(updaterURL).openConnection(); + + InputStream iStr = conn.getInputStream(); + OutputStream oStr = Files.newOutputStream(path); + + byte[] data = new byte[1024]; + int dataLength = 0; + while ((dataLength = iStr.read(data, 0, data.length)) > 0) { + oStr.write(data, 0, dataLength); + } + oStr.close(); + } + + private static void startExeFile(String parameter, Path fileExeFolder) { + NativeLauncher.executeAsAdministrator(fileExeFolder.toAbsolutePath().toString(), parameter); + System.exit(0); + } + + private static void startJarFile(String parameter, Path fileJarFolder) throws IOException { + ProcessBuilder builder = new ProcessBuilder("java", "-jar", fileJarFolder.toAbsolutePath().toString(), parameter); + builder.start(); + System.exit(0); + } + + @Override + public void loadSettings(Profile profile) { + automaticSearchCheckBox.setSelected(profile.getProfileSettings().isAutoUpdate()); + } + + @Override + public void saveSettings(Profile profile) { + profile.getProfileSettings().setAutoUpdate(automaticSearchCheckBox.isSelected()); + } + + @Override + public boolean needReload() { + return false; + } + + @Override + public boolean validSettings() { + return true; + } + + @Override + public String name() { + return Localization.getString(Strings.UI_Window_Settings_Updates_Title); + } + + private static void showErrorMessage(String message, Optional<Image> icon, Window owner) { + if (!Platform.isFxApplicationThread()) { + Platform.runLater(() -> showErrorMessage(message, icon, owner)); + return; + } + + Alert alert = new Alert(AlertType.ERROR); + alert.initOwner(owner); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(message); + if (icon.isPresent()) { + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.getIcons().add(icon.get()); + } + alert.showAndWait(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/DoubleFeedbackViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/DoubleFeedbackViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..24c6cfb81e5544f1beb8ac696a4a96555a170cf8 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/DoubleFeedbackViewController.java @@ -0,0 +1,122 @@ +package de.tobias.playpad.viewcontroller.option.feedback; + +import java.util.Optional; + +import org.controlsfx.control.PopOver; +import org.controlsfx.control.PopOver.ArrowLocation; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.action.feedback.DisplayableFeedbackColor; +import de.tobias.playpad.action.feedback.DoubleSimpleFeedback; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.view.ColorView; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.layout.HBox; +import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import javafx.scene.shape.Rectangle; + +public class DoubleFeedbackViewController extends ContentViewController { + + @FXML private HBox defaultColorParent; + @FXML private Button colorChooseDefaultButton; + @FXML private Rectangle colorPreviewDefault; + + @FXML private HBox eventColorParent; + @FXML private Button colorChooseEventButton; + @FXML private Rectangle colorPreviewEvent; + + private PopOver colorChooser; + + private DoubleSimpleFeedback feedback; + + public DoubleFeedbackViewController(DoubleSimpleFeedback feedback, DisplayableFeedbackColor[] colors) { + super("doubleFeedback", "de/tobias/playpad/assets/view/option/feedback/", PlayPadMain.getUiResourceBundle()); + this.feedback = feedback; + + Optional<Device> deviceOptional = Midi.getInstance().getMidiDevice(); + deviceOptional.ifPresent(device -> + { + DisplayableFeedbackColor colorDefault = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.STANDARD)); + if (colorDefault != null) { + colorPreviewDefault.setFill(colorDefault.getPaint()); + setColorChooseButtonColor(colorDefault.getPaint(), colorChooseDefaultButton); + } + DisplayableFeedbackColor colorPlay = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.EVENT)); + if (colorPlay != null) { + colorPreviewEvent.setFill(colorPlay.getPaint()); + setColorChooseButtonColor(colorPlay.getPaint(), colorChooseEventButton); + } + }); + } + + @Override + public void init() { + FontIcon iconDefault = new FontIcon(FontAwesomeType.ARROW_CIRCLE_DOWN); + iconDefault.getStyleClass().remove(FontIcon.STYLE_CLASS); + colorChooseDefaultButton.setGraphic(iconDefault); + colorPreviewDefault.widthProperty().bind(colorChooseDefaultButton.widthProperty()); + + FontIcon iconEvent = new FontIcon(FontAwesomeType.ARROW_CIRCLE_DOWN); + iconEvent.getStyleClass().remove(FontIcon.STYLE_CLASS); + colorChooseEventButton.setGraphic(iconEvent); + colorPreviewEvent.widthProperty().bind(colorChooseEventButton.widthProperty()); + } + + @FXML + private void colorChooseButtonHandler(ActionEvent event) { + if (colorChooser == null) { + colorChooser = new PopOver(); + Midi.getInstance().getMidiDevice().ifPresent((device) -> + { + DisplayableFeedbackColor color = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.STANDARD)); + if (event.getSource() == colorChooseDefaultButton) { + color = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.STANDARD)); + } else if (event.getSource() == colorChooseEventButton) { + color = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.EVENT)); + } + + ColorView colorView = new ColorView(color, device.getColors(), item -> + { + colorChooser.hide(); + if (item instanceof DisplayableFeedbackColor) { + if (event.getSource() == colorChooseDefaultButton) { + feedback.setFeedbackDefaultValue(((DisplayableFeedbackColor) item).midiVelocity()); + colorPreviewDefault.setFill(item.getPaint()); + setColorChooseButtonColor(item.getPaint(), colorChooseDefaultButton); + } else if (event.getSource() == colorChooseEventButton) { + feedback.setFeedbackEventValue(((DisplayableFeedbackColor) item).midiVelocity()); + colorPreviewEvent.setFill(item.getPaint()); + setColorChooseButtonColor(item.getPaint(), colorChooseEventButton); + } + } + }); + + colorChooser.setContentNode(colorView); + colorChooser.setDetachable(false); + colorChooser.setOnHiding(e -> colorChooser = null); + colorChooser.setCornerRadius(5); + colorChooser.setArrowLocation(ArrowLocation.LEFT_CENTER); + colorChooser.show((Node) event.getSource()); + }); + } + + } + + private void setColorChooseButtonColor(Paint inputColor, Button button) { + Color color; + if (inputColor.equals(Color.BLACK)) + color = Color.WHITE; + else + color = Color.BLACK; + ((FontIcon) button.getGraphic()).setColor(color); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/SingleFeedbackViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/SingleFeedbackViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..7a737802e3b7579ce6ea35d480f8cb79356fb002 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/feedback/SingleFeedbackViewController.java @@ -0,0 +1,98 @@ +package de.tobias.playpad.viewcontroller.option.feedback; + +import java.util.Optional; + +import org.controlsfx.control.PopOver; +import org.controlsfx.control.PopOver.ArrowLocation; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.action.feedback.DisplayableFeedbackColor; +import de.tobias.playpad.action.feedback.FeedbackMessage; +import de.tobias.playpad.action.feedback.SingleSimpleFeedback; +import de.tobias.playpad.action.mididevice.Device; +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.view.ColorView; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.layout.HBox; +import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import javafx.scene.shape.Rectangle; + +public class SingleFeedbackViewController extends ContentViewController { + + @FXML private HBox defaultColorParent; + @FXML private Button colorChooseDefaultButton; + @FXML private Rectangle colorPreviewDefault; + + private PopOver colorChooser; + + private SingleSimpleFeedback feedback; + + public SingleFeedbackViewController(SingleSimpleFeedback feedback, DisplayableFeedbackColor[] colors) { + super("singleFeedback", "de/tobias/playpad/assets/view/option/feedback/", PlayPadMain.getUiResourceBundle()); + this.feedback = feedback; + + Optional<Device> deviceOptional = Midi.getInstance().getMidiDevice(); + deviceOptional.ifPresent(device -> + { + DisplayableFeedbackColor colorDefault = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.STANDARD)); + if (colorDefault != null) { + colorPreviewDefault.setFill(colorDefault.getPaint()); + setColorChooseButtonColor(colorDefault.getPaint(), colorChooseDefaultButton); + } + }); + } + + @Override + public void init() { + FontIcon iconDefault = new FontIcon(FontAwesomeType.ARROW_CIRCLE_DOWN); + iconDefault.getStyleClass().remove(FontIcon.STYLE_CLASS); + colorChooseDefaultButton.setGraphic(iconDefault); + colorPreviewDefault.widthProperty().bind(colorChooseDefaultButton.widthProperty()); + } + + @FXML + private void colorChooseButtonHandler(ActionEvent event) { + if (colorChooser == null) { + colorChooser = new PopOver(); + Midi.getInstance().getMidiDevice().ifPresent((device) -> + { + DisplayableFeedbackColor color = device.getColor(feedback.getValueForFeedbackMessage(FeedbackMessage.STANDARD)); + + ColorView colorView = new ColorView(color, device.getColors(), item -> + { + colorChooser.hide(); + if (item instanceof DisplayableFeedbackColor) { + if (event.getSource() == colorChooseDefaultButton) { + feedback.setFeedbackValue(((DisplayableFeedbackColor) item).midiVelocity()); + colorPreviewDefault.setFill(item.getPaint()); + setColorChooseButtonColor(item.getPaint(), colorChooseDefaultButton); + } + } + }); + + colorChooser.setContentNode(colorView); + colorChooser.setDetachable(false); + colorChooser.setOnHiding(e -> colorChooser = null); + colorChooser.setCornerRadius(5); + colorChooser.setArrowLocation(ArrowLocation.LEFT_CENTER); + colorChooser.show((Node) event.getSource()); + }); + } + } + + private void setColorChooseButtonColor(Paint inputColor, Button button) { + Color color; + if (inputColor.equals(Color.BLACK)) + color = Color.WHITE; + else + color = Color.BLACK; + ((FontIcon) button.getGraphic()).setColor(color); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..006630b24349cc74a2e18dbf99903f2524fd0226 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/GeneralPadTabViewController.java @@ -0,0 +1,95 @@ +package de.tobias.playpad.viewcontroller.option.pad; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.TimeMode; +import de.tobias.playpad.viewcontroller.PadSettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.EnumCell; +import de.tobias.utils.util.Localization; +import javafx.beans.value.ChangeListener; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Slider; +import javafx.scene.control.TextField; +import javafx.stage.Stage; + +public class GeneralPadTabViewController extends PadSettingsTabViewController { + + @FXML private TextField titleTextField; + @FXML private Slider volumeSlider; + @FXML private CheckBox repeatCheckBox; + + @FXML private CheckBox customTimeDisplayCheckBox; + @FXML private ComboBox<TimeMode> timeDisplayComboBox; + + @FXML private Button deleteButton; + + private Pad pad; + + private ChangeListener<Number> volumeListener; + + public GeneralPadTabViewController(Pad pad) { + super("generalTab", "de/tobias/playpad/assets/view/option/pad/", PlayPadMain.getUiResourceBundle()); + this.pad = pad; + } + + @Override + public void init() { + // Init Listener + volumeListener = (a, b, c) -> pad.setVolume(c.doubleValue() / 100.0); + + volumeSlider.valueProperty().addListener(volumeListener); + + customTimeDisplayCheckBox.selectedProperty().addListener((a, b, c) -> + { + timeDisplayComboBox.setDisable(!c); + if (c && !pad.isCustomTimeMode()) + pad.setTimeMode(TimeMode.REST); + else if (b && pad.isCustomTimeMode()) + pad.setTimeMode(null); + + }); + timeDisplayComboBox.getItems().addAll(TimeMode.values()); + timeDisplayComboBox.setButtonCell(new EnumCell<>(Strings.Pad_TimeMode_BaseName)); + timeDisplayComboBox.setCellFactory(list -> new EnumCell<>(Strings.Pad_TimeMode_BaseName)); + } + + @Override + public String getName() { + return Localization.getString(Strings.UI_Window_PadSettings_General_Title); + } + + @Override + public void loadSettings(Pad pad) { + // Bindings + titleTextField.textProperty().bindBidirectional(pad.nameProperty()); + repeatCheckBox.selectedProperty().bindBidirectional(pad.loopProperty()); + timeDisplayComboBox.valueProperty().bindBidirectional(pad.timeModeProperty()); + + volumeSlider.setValue(pad.getVolume() * 100); + + // is Custom TimeMode Actvie + customTimeDisplayCheckBox.setSelected(pad.isCustomTimeMode()); + if (!pad.isCustomTimeMode()) { + timeDisplayComboBox.setDisable(true); + } + } + + @Override + public void saveSettings(Pad pad) { + titleTextField.textProperty().unbindBidirectional(pad.nameProperty()); + repeatCheckBox.selectedProperty().unbindBidirectional(pad.loopProperty()); + timeDisplayComboBox.valueProperty().unbindBidirectional(pad.timeModeProperty()); + } + + // Listener + @FXML + private void deleteButtonHandler(ActionEvent event) { + pad.clear(); + ((Stage) getStage()).close(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/LayoutPadTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/LayoutPadTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..775bdb6dd999e39b15e072cf6fee2fc1b0e3f57c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/LayoutPadTabViewController.java @@ -0,0 +1,90 @@ +package de.tobias.playpad.viewcontroller.option.pad; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.Strings; +import de.tobias.playpad.layout.CartLayout; +import de.tobias.playpad.layout.LayoutRegistry; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.CartLayoutViewController; +import de.tobias.playpad.viewcontroller.PadSettingsTabViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.layout.VBox; + +public class LayoutPadTabViewController extends PadSettingsTabViewController { + + @FXML private VBox layoutContainer; + @FXML private CheckBox enableLayoutCheckBox; + private CartLayoutViewController layoutViewController; + + private Pad pad; + + public LayoutPadTabViewController(Pad pad) { + super("layoutTab", "de/tobias/playpad/assets/view/option/pad/", PlayPadMain.getUiResourceBundle()); + this.pad = pad; + } + + private void setLayoutController(CartLayoutViewController cartLayoutViewController) { + if (layoutViewController != null) + layoutContainer.getChildren().remove(layoutViewController.getParent()); + + if (cartLayoutViewController != null) { + layoutViewController = cartLayoutViewController; + layoutContainer.getChildren().add(layoutViewController.getParent()); + } + } + + @Override + public void init() { + enableLayoutCheckBox.selectedProperty().addListener((a, b, c) -> + { + if (c && !pad.isCustomLayout()) { + try { + pad.setCustomLayout(true); + try { + String layoutType = Profile.currentProfile().getProfileSettings().getLayoutType(); + CartLayout layout = pad.getLayout(layoutType); + setLayoutController(LayoutRegistry.getLayout(layoutType).getCartLayoutViewController(layout)); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Layout_Load, e.getMessage())); + } + } catch (Exception e) { + showErrorMessage(Localization.getString(Strings.Error_Standard_Gen, e.getLocalizedMessage())); + e.printStackTrace(); + } + } else if (!c && pad.isCustomLayout()) { + pad.setCustomLayout(false); + setLayoutController(null); + } + }); + } + + @Override + public String getName() { + return Localization.getString(Strings.UI_Window_PadSettings_Layout_Title); + } + + @Override + public void loadSettings(Pad pad) { + enableLayoutCheckBox.setSelected(pad.isCustomLayout()); + if (pad.isCustomLayout()) { + try { + String layoutType = Profile.currentProfile().getProfileSettings().getLayoutType(); + CartLayout layout = pad.getLayout(layoutType); + setLayoutController(LayoutRegistry.getLayout(layoutType).getCartLayoutViewController(layout)); + } catch (Exception e) { + e.printStackTrace(); + showErrorMessage(Localization.getString(Strings.Error_Layout_Load, e.getMessage())); + } + } + } + + @Override + public void saveSettings(Pad pad) { + PlayPadPlugin.getImplementation().getMainViewController().loadUserCss(); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..8a4f591202f5b74d90a8ccb4f7c995e52d14fed9 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PadSettingsViewController.java @@ -0,0 +1,128 @@ +package de.tobias.playpad.viewcontroller.option.pad; + +import java.util.ArrayList; +import java.util.List; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.viewcontroller.IPadSettingsViewController; +import de.tobias.playpad.viewcontroller.PadSettingsTabViewController; +import de.tobias.utils.ui.ViewController; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.stage.Stage; +import javafx.stage.Window; + +public class PadSettingsViewController extends ViewController implements IPadSettingsViewController { + + private Pad pad; + + @FXML private TabPane tabPane; + protected List<PadSettingsTabViewController> tabs = new ArrayList<>(); + + @FXML private Button finishButton; + + public PadSettingsViewController(Pad pad, Window owner) { + super("padSettingsView", "de/tobias/playpad/assets/view/option/pad/", null, PlayPadMain.getUiResourceBundle()); + this.pad = pad; + + addTab(new GeneralPadTabViewController(pad)); + addTab(new LayoutPadTabViewController(pad)); + addTab(new PlayerPadTabViewController(pad)); + addTab(new TriggerPadTabViewController(pad)); + + if (pad.getContent() != null) { + try { + PadSettingsTabViewController contentTab = PadContentRegistry.getPadContentConnect(pad.getContent().getType()) + .getSettingsViewController(pad); + if (contentTab != null) + addTab(contentTab); + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> + { + try { + l.onInit(this); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + getStage().initOwner(owner); + + // Show Current Settings + showCurrentSettings(); + getStage().setTitle(Localization.getString(Strings.UI_Window_PadSettings_Title, pad.getIndexReadable(), pad.getName())); + } + + @Override + public void init() { + addCloseKeyShortcut(() -> finishButton.fire()); + } + + @Override + public void initStage(Stage stage) { + PlayPadMain.stageIcon.ifPresent(stage.getIcons()::add); + + stage.setMinWidth(650); + stage.setMinHeight(500); + + Profile.currentProfile().currentLayout().applyCss(getStage()); + } + + private void showCurrentSettings() { + for (PadSettingsTabViewController padSettingsTabViewController : tabs) { + padSettingsTabViewController.loadSettings(pad); + } + } + + @Override + public void addTab(PadSettingsTabViewController controller) { + tabs.add(controller); + + Tab tab = new Tab(controller.getName(), controller.getParent()); + tabPane.getTabs().add(tab); + } + + @Override + public Pad getPad() { + return pad; + } + + @Override + public boolean closeRequest() { + saveChanges(); + + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> l.onClose(this)); + return true; + } + + private void saveChanges() { + for (PadSettingsTabViewController controller : tabs) { + controller.saveSettings(pad); + } + } + + @FXML + private void finishButtonHandler(ActionEvent event) { + saveChanges(); + // Listener + PlayPadPlugin.getImplementation().getPadSettingsViewListener().forEach(l -> l.onClose(this)); + getStage().close(); + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PlayerPadTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PlayerPadTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..6c6274b3da4766dfbba104f2a49e2f59a0648e8c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/PlayerPadTabViewController.java @@ -0,0 +1,92 @@ +package de.tobias.playpad.viewcontroller.option.pad; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Fade; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.viewcontroller.PadSettingsTabViewController; +import de.tobias.playpad.viewcontroller.settings.FadeViewController; +import de.tobias.playpad.viewcontroller.settings.WarningFeedbackViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.layout.VBox; + +public class PlayerPadTabViewController extends PadSettingsTabViewController { + + @FXML private CheckBox customFadeCheckBox; + @FXML private VBox fadeContainer; + private FadeViewController fadeViewController; + + @FXML private VBox warningFeedbackContainer; + @FXML private CheckBox warningEnableCheckBox; + private WarningFeedbackViewController warningFeedbackViewController; + + private Pad pad; + + public PlayerPadTabViewController(Pad pad) { + super("playerTab", "de/tobias/playpad/assets/view/option/pad/", PlayPadMain.getUiResourceBundle()); + this.pad = pad; + } + + @Override + public void init() { + // Embed ViewController + fadeViewController = new FadeViewController(); + fadeContainer.getChildren().add(fadeViewController.getParent()); + + warningFeedbackViewController = new WarningFeedbackViewController(null); + warningFeedbackContainer.getChildren().add(warningFeedbackViewController.getParent()); + + customFadeCheckBox.selectedProperty().addListener((a, b, c) -> + { + fadeContainer.setDisable(!c); + if (c && !pad.isCustomFade()) + pad.setFade(new Fade()); + else if (!c && pad.isCustomFade()) + pad.setFade(null); + + if (c) + fadeViewController.setFade(pad.getFade()); + }); + + warningEnableCheckBox.selectedProperty().addListener((a, b, c) -> + { + warningFeedbackContainer.setDisable(!c); + if (c && !pad.isCustomWarning()) + pad.setWarning(new Warning()); + else if (!c && pad.isCustomWarning()) + pad.setWarning(null); + + if (c) + warningFeedbackViewController.setPadWarning(pad); + }); + } + + @Override + public String getName() { + return Localization.getString(Strings.UI_Window_PadSettings_Player_Title); + } + + @Override + public void loadSettings(Pad pad) { + if (pad.isCustomFade()) + fadeViewController.setFade(pad.getFade()); + + customFadeCheckBox.setSelected(pad.isCustomFade()); + if (!pad.isCustomFade()) { + fadeContainer.setDisable(true); + } + + warningEnableCheckBox.setSelected(pad.isCustomWarning()); + if (!pad.isCustomWarning()) { + warningFeedbackContainer.setDisable(true); + } + } + + @Override + public void saveSettings(Pad pad) { + + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..f6fb894434191e4df9bb6fe509dfdac2bc9c0413 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/TriggerPadTabViewController.java @@ -0,0 +1,80 @@ +package de.tobias.playpad.viewcontroller.option.pad; + +import java.util.HashMap; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.tigger.Trigger; +import de.tobias.playpad.tigger.TriggerPoint; +import de.tobias.playpad.trigger.TriggerWrapper; +import de.tobias.playpad.viewcontroller.PadSettingsTabViewController; +import de.tobias.playpad.viewcontroller.cell.DisplayableTreeCell; +import de.tobias.playpad.viewcontroller.option.pad.trigger.TriggerPointViewController; +import de.tobias.utils.util.Localization; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.TreeItem; +import javafx.scene.control.TreeView; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +public class TriggerPadTabViewController extends PadSettingsTabViewController implements ChangeListener<TreeItem<TriggerWrapper>> { + + @FXML private TreeView<TriggerWrapper> treeView; + @FXML private VBox contentView; + + private Pad pad; + + public TriggerPadTabViewController(Pad pad) { + super("triggerTab", "de/tobias/playpad/assets/view/option/pad/", PlayPadMain.getUiResourceBundle()); + this.pad = pad; + } + + @Override + public void init() { + treeView.setCellFactory(list -> new DisplayableTreeCell<>()); + treeView.getSelectionModel().selectedItemProperty().addListener(this); + } + + private void createTreeView() { + HashMap<TriggerPoint, Trigger> triggers = pad.getTriggers(); + TreeItem<TriggerWrapper> rootItem = new TreeItem<>(); + + // Sort the tpyes for the treeview + for (TriggerPoint point : TriggerPoint.values()) { + Trigger trigger = triggers.get(point); + + TreeItem<TriggerWrapper> triggerItem = new TreeItem<>(new TriggerWrapper(trigger)); + rootItem.getChildren().add(triggerItem); + } + + treeView.setRoot(rootItem); + } + + public void changed(ObservableValue<? extends TreeItem<TriggerWrapper>> observable, TreeItem<TriggerWrapper> oldValue, + TreeItem<TriggerWrapper> newValue) { + contentView.getChildren().clear(); + + if (newValue != null) { + TriggerWrapper triggerWrapper = newValue.getValue(); + TriggerPointViewController controller = new TriggerPointViewController(triggerWrapper); + contentView.getChildren().setAll(controller.getParent()); + VBox.setVgrow(controller.getParent(), Priority.ALWAYS); + } + } + + @Override + public String getName() { + return Localization.getString(Strings.UI_Window_PadSettings_Trigger_Title); + } + + @Override + public void loadSettings(Pad pad) { + createTreeView(); + } + + @Override + public void saveSettings(Pad pad) {} +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..5e5f457bb24a08f10381e3c0053fe3ffb2b73482 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/CartTriggerViewController.java @@ -0,0 +1,46 @@ +package de.tobias.playpad.viewcontroller.option.pad.trigger; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.trigger.CartTriggerItem; +import de.tobias.utils.ui.ContentViewController; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextField; + + +public class CartTriggerViewController extends ContentViewController { + + @FXML private ComboBox<PadStatus> statusComboBox; + @FXML private CheckBox allCartsCheckbox; + @FXML private TextField cartTextField; + + private CartTriggerItem item; + + public CartTriggerViewController(CartTriggerItem item) { + super("cartTrigger", "de/tobias/playpad/assets/view/option/pad/trigger/", PlayPadMain.getUiResourceBundle()); + this.item = item; + + statusComboBox.setValue(item.getNewStatus()); + allCartsCheckbox.setSelected(item.isAllCarts()); + cartTextField.setText(item.getCartsString()); + } + + @Override + public void init() { + statusComboBox.getItems().addAll(PadStatus.PLAY, PadStatus.PAUSE, PadStatus.STOP); + statusComboBox.valueProperty().addListener((a, b, c) -> item.setNewStatus(c)); + + allCartsCheckbox.selectedProperty().addListener((a, b, c) -> + { + cartTextField.setDisable(c); + item.setAllCarts(c); + }); + cartTextField.textProperty().addListener((a, b, c) -> + { + if (c != null && !c.isEmpty()) + item.setCartsString(c); + }); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..78e89182813afc0a68d348c1e1f91dd30a0e7f1b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerPointViewController.java @@ -0,0 +1,82 @@ +package de.tobias.playpad.viewcontroller.option.pad.trigger; + +import java.util.Set; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.playpad.tigger.TriggerItemConnect; +import de.tobias.playpad.tigger.TriggerRegistry; +import de.tobias.playpad.trigger.TriggerWrapper; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.ui.icon.FontAwesomeType; +import de.tobias.utils.ui.icon.FontIcon; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Separator; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +public class TriggerPointViewController extends ContentViewController { + + @FXML private VBox itemView; + @FXML private HBox buttonBox; + + private TriggerWrapper triggerWrapper; + + public TriggerPointViewController(TriggerWrapper triggerWrapper) { + super("triggerPoint", "de/tobias/playpad/assets/view/option/pad/trigger/", PlayPadMain.getUiResourceBundle()); + this.triggerWrapper = triggerWrapper; + + for (TriggerItem item : triggerWrapper.getTrigger().getItems()) + showTriggerItem(item); + } + + @Override + public void init() { + Set<String> types = TriggerRegistry.getTypes(); + types.stream().sorted().forEach(item -> + { + Button button = new Button(TriggerRegistry.getTriggerConnect(item).toString(), new FontIcon(FontAwesomeType.PLUS_CIRCLE)); + button.setContentDisplay(ContentDisplay.TOP); + button.setPrefWidth(150); + + button.setOnAction(e -> + { + TriggerItemConnect connect = TriggerRegistry.getTriggerConnect(item); + TriggerItem triggerItem = connect.newInstance(triggerWrapper.getTrigger()); + + triggerWrapper.addItem(triggerItem); + showTriggerItem(triggerItem); + }); + buttonBox.getChildren().add(button); + }); + } + + private void showTriggerItem(TriggerItem item) { + TriggerItemConnect connect = TriggerRegistry.getTriggerConnect(item.getType()); + + VBox itemBox = new VBox(14); + ContentViewController contentViewController = connect.getSettingsController(item); + if (contentViewController != null) { + itemBox.getChildren().add(contentViewController.getParent()); + + ContentViewController timeViewController = new TriggerTimeViewController(item); + itemBox.getChildren().add(timeViewController.getParent()); + + Button deleteButton = new Button("", new FontIcon(FontAwesomeType.TRASH)); + HBox hbox = new HBox(itemBox, deleteButton); + hbox.setSpacing(14); + + VBox rootBox = new VBox(14.0, hbox, new Separator()); + + itemView.getChildren().addAll(rootBox); + + deleteButton.setOnAction((e) -> + { + triggerWrapper.removeItem(item); + itemView.getChildren().removeAll(rootBox); + }); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerTimeViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerTimeViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..b1215391fa42224f849baa66c26afede6489bf07 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/option/pad/trigger/TriggerTimeViewController.java @@ -0,0 +1,38 @@ +package de.tobias.playpad.viewcontroller.option.pad.trigger; + +import java.util.Optional; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.tigger.TriggerItem; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.TimeUtils; +import javafx.fxml.FXML; +import javafx.scene.control.TextField; +import javafx.util.Duration; + +public class TriggerTimeViewController extends ContentViewController { + + @FXML private TextField timeTextField; + + private TriggerItem item; + + public TriggerTimeViewController(TriggerItem item) { + super("triggerTime", "de/tobias/playpad/assets/view/option/pad/trigger/", PlayPadMain.getUiResourceBundle()); + this.item = item; + + timeTextField.setText(String.valueOf(item.getDurationFromPoint().toSeconds())); + } + + @Override + public void init() { + timeTextField.textProperty().addListener((a, b, c) -> + { + Optional<Duration> duration = TimeUtils.parse(c); + if (duration.isPresent()) { + item.setDurationFromPoint(duration.get()); + } + timeTextField.pseudoClassStateChanged(PseudoClasses.ERROR_CLASS, !duration.isPresent()); + }); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragHandler.java b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..dd6b1c83f66fd9ec94de0e1c644f862eceda730b --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragHandler.java @@ -0,0 +1,204 @@ +package de.tobias.playpad.viewcontroller.pad; + +import java.io.File; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.audio.AudioRegistry; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.plugin.ExtensionHandler; +import de.tobias.playpad.plugin.PlayPadPlugin; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.view.AudioPadView; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.Refreshable; +import de.tobias.utils.util.Localization; +import javafx.scene.SnapshotParameters; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.TransferMode; + +// TODO Renew class +public class PadDragHandler<T extends Refreshable & NotificationHandler> { + + private static final String REGEX = "[0-9]+"; + private Pad pad; + final private AudioPadView view; + final private T t; + + private static AudioPadView lastDraggedOver; + private static boolean dndMode; + private static Project project; + + public PadDragHandler(Pad pad, AudioPadView view, T t) { + this.pad = pad; + this.view = view; + this.t = t; + + // Drag and Drop + view.setOnDragOver(event -> dragOver(event)); + view.setOnDragExited(event -> dragExited()); + view.setOnDragDropped(event -> dragDropped(event)); + view.setOnDragDetected(event -> dragDetacted(event)); + } + + private void dragOver(DragEvent event) { + if (event.getGestureSource() != this && event.getDragboard().hasFiles()) { + if (event.getDragboard().getFiles().get(0).isFile()) { + if (PadViewController.getPlayedPlayers() > 0) { + showLiveModeLabel(); + } + File file = event.getDragboard().getFiles().get(0); + + // Build In Filesupport + for (String extension : AudioRegistry.geAudioType().getSupportedTypes()) { + if (file.getName().toLowerCase().matches("." + extension)) { + event.acceptTransferModes(TransferMode.LINK); + return; + } + } + + // Plugins + for (ExtensionHandler extensionHandler : PlayPadPlugin.getImplementation().getExtensionsHandler()) { + for (String extension : extensionHandler.getExtensions()) { + if (file.getName().toLowerCase().matches("." + extension)) { + event.acceptTransferModes(TransferMode.LINK); + return; + } + } + } + } + } + + if (event.getDragboard().hasString() && event.getDragboard().getString().trim().matches(REGEX)) { + int padID = Integer.valueOf(event.getDragboard().getString()); + if (padID != view.getController().getPad().getIndex()) { + + // Live Mode + if (PadViewController.getPlayedPlayers() > 0) { + showLiveModeLabel(); + } else { + event.acceptTransferModes(TransferMode.MOVE); + double y = event.getY(); + if (y < view.getHeight() / 2) { + if (lastDraggedOver != null) { + view.pseudoClassState(PseudoClasses.DRAG_RELACE_CLASS, false); + view.pseudoClassState(PseudoClasses.DRAG_MOVE_CLASS, false); + } + view.pseudoClassState(PseudoClasses.DRAG_RELACE_CLASS, false); + view.pseudoClassState(PseudoClasses.DRAG_MOVE_CLASS, true); + lastDraggedOver = view; + } else { + if (lastDraggedOver != null) { + view.pseudoClassState(PseudoClasses.DRAG_RELACE_CLASS, false); + view.pseudoClassState(PseudoClasses.DRAG_MOVE_CLASS, false); + } + view.pseudoClassState(PseudoClasses.DRAG_MOVE_CLASS, false); + view.pseudoClassState(PseudoClasses.DRAG_RELACE_CLASS, true); + lastDraggedOver = view; + } + } + } + } + event.consume(); + } + + private void dragExited() { + if (lastDraggedOver != null) { + view.pseudoClassState(PseudoClasses.DRAG_RELACE_CLASS, false); + view.pseudoClassState(PseudoClasses.DRAG_MOVE_CLASS, false); + lastDraggedOver = null; + } + } + + private void dragDropped(DragEvent event) { + // Live Mode + if (PadViewController.getPlayedPlayers() > 0) { + showLiveModeLabel(); + } else { + Dragboard db = event.getDragboard(); + boolean success = false; + if (db.hasFiles()) { + success = true; + File file = db.getFiles().get(0); + + boolean custom = false; + for (ExtensionHandler extensionHandler : PlayPadPlugin.getImplementation().getExtensionsHandler()) { + for (String extension : extensionHandler.getExtensions()) { + if (file.getName().toLowerCase().matches("." + extension)) { + extensionHandler.handle(file.toPath(), pad); + custom = true; + break; + } + } + } + if (!custom) { + this.pad.setPath(file.toPath()); + } + } + + if (db.hasString() && db.getString().matches(REGEX)) { + double y = event.getY(); + if (y < view.getHeight() / 2) { + int padID = Integer.valueOf(db.getString()); + project.movePads(padID, pad.getIndex()); + t.refreshUI(); + success = true; + } else { + int padID = Integer.valueOf(db.getString()); + project.replacePads(padID, pad.getIndex()); + t.refreshUI(); + success = true; + } + } + + event.setDropCompleted(success); + event.consume(); + } + } + + private void dragDetacted(MouseEvent event) { + // Live Mode + if (PadViewController.getPlayedPlayers() == 0) { + if (dndMode) { + Dragboard storeImage = view.startDragAndDrop(TransferMode.MOVE); + storeImage.setDragView(view.snapshot(new SnapshotParameters(), null)); + + ClipboardContent content = new ClipboardContent(); + content.putString(String.valueOf(pad.getIndex())); + storeImage.setContent(content); + + event.consume(); + } + } + } + + public static void setDndMode(boolean dndMode) { + PadDragHandler.dndMode = dndMode; + } + + public static void setLastDraggedOver(AudioPadView lastDraggedOver) { + PadDragHandler.lastDraggedOver = lastDraggedOver; + } + + public void setPad(Pad pad) { + this.pad = pad; + } + + public static void setProject(Project project) { + PadDragHandler.project = project; + } + + private boolean displayLiveLabel; + + private synchronized void showLiveModeLabel() { + if (!displayLiveLabel) { + displayLiveLabel = true; + t.notify(Localization.getString(Strings.Error_Pad_Livemode), PlayPadMain.notificationDisplayTimeMillis, + () -> displayLiveLabel = false); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragListener.java b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragListener.java new file mode 100644 index 0000000000000000000000000000000000000000..0de732ca29d63fb83fade6f6d295b7b8ed94a429 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadDragListener.java @@ -0,0 +1,179 @@ +package de.tobias.playpad.viewcontroller.pad; + +import java.io.File; +import java.util.Collection; +import java.util.Set; + +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.pad.drag.PadDragMode; +import de.tobias.playpad.pad.drag.PadDragModeRegistery; +import de.tobias.playpad.project.Project; +import de.tobias.playpad.view.FileDragOptionView; +import de.tobias.playpad.view.PadDragOptionView; +import de.tobias.playpad.view.PadView; +import de.tobias.utils.util.FileUtils; +import javafx.scene.SnapshotParameters; +import javafx.scene.image.WritableImage; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.TransferMode; +import javafx.scene.paint.Color; + +public class PadDragListener { + + private static final String REGEX = "[0-9]+"; + private Pad pad; + final private PadView view; + + private static boolean dndMode; + private static Project project; + + private PadDragOptionView padHud; + private FileDragOptionView fileHud; + + public PadDragListener(Pad pad, PadView view) { + this.pad = pad; + this.view = view; + + // Drag and Drop + view.setOnDragOver(event -> dragOver(event)); + view.setOnDragExited(event -> dragExited()); + view.setOnDragDropped(event -> dragDropped(event)); + view.setOnDragDetected(event -> dragDetacted(event)); + } + + private void dragOver(DragEvent event) { + if (event.getGestureSource() != this && event.getDragboard().hasFiles()) { + if (event.getDragboard().getFiles().get(0).isFile()) { + File file = event.getDragboard().getFiles().get(0); + + // Build In Filesupport + try { + Set<PadContentConnect> connects = PadContentRegistry.getPadContentConnectsForFile(file.toPath()); + + if (!connects.isEmpty()) { + if (fileHud == null) { + fileHud = new FileDragOptionView(view); + } + fileHud.showDropOptions(connects); + + event.acceptTransferModes(TransferMode.LINK); + return; + } + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + } + } + + if (event.getDragboard().hasString() && event.getDragboard().getString().trim().matches(REGEX)) { + int padID = Integer.valueOf(event.getDragboard().getString()); + if (padID != view.getController().getPad().getIndex()) { + + Collection<PadDragMode> connects = PadDragModeRegistery.getValues(); + + if (!connects.isEmpty()) { + if (padHud == null) { + padHud = new PadDragOptionView(view); + } + padHud.showDropOptions(connects); + + event.acceptTransferModes(TransferMode.MOVE); + } + } + } + event.consume(); + } + + private void dragExited() { + if (padHud != null) { + padHud.hide(); + } + if (fileHud != null) { + fileHud.hide(); + } + } + + private void dragDropped(DragEvent event) { + Dragboard db = event.getDragboard(); + boolean success = false; + if (db.hasFiles()) { + success = true; + File file = db.getFiles().get(0); + + PadContentConnect connect = fileHud.getSelectedConnect(); + if (connect != null) { + PadContent content = pad.getContent(); + if (pad.getContent() == null || !pad.getContent().getType().equals(connect.getType())) { + content = connect.newInstance(pad); + } + + content.handlePath(file.toPath()); + this.pad.setContent(content); + this.pad.setName(FileUtils.getFilenameWithoutExtention(file.toPath().getFileName())); + + view.setPreviewContent(pad); + view.addDefaultButton(pad); + } + } + + if (db.hasString() && db.getString().matches(REGEX)) { + int padID = Integer.valueOf(db.getString()); + + PadDragMode mode = padHud.getSelectedPadDragMode(); + mode.handle(padID, pad.getIndex(), project); + padHud.hide(); + + PlayPadPlugin.getImplementation().getMainViewController() + .showPage(PlayPadPlugin.getImplementation().getMainViewController().getPage()); + + event.setDropCompleted(success); + event.consume(); + } + } + + private void dragDetacted(MouseEvent event) { + if (dndMode) { + Dragboard dragboard = view.startDragAndDrop(TransferMode.MOVE); + + SnapshotParameters parameters = new SnapshotParameters(); + parameters.setFill(Color.TRANSPARENT); + WritableImage snapshot = view.snapshot(parameters, null); + for (int x = 0; x < snapshot.getWidth(); x++) { + for (int y = 0; y < snapshot.getHeight(); y++) { + Color oldColor = snapshot.getPixelReader().getColor(x, y).darker().darker(); + snapshot.getPixelWriter().setColor(x, y, + new Color(oldColor.getRed(), oldColor.getGreen(), oldColor.getBlue(), oldColor.getOpacity() * 0.5)); + } + } + + dragboard.setDragView(snapshot); + + ClipboardContent content = new ClipboardContent(); + content.putString(String.valueOf(pad.getIndex())); + dragboard.setContent(content); + + event.consume(); + } + } + + public static void setDndMode(boolean dndMode) { + PadDragListener.dndMode = dndMode; + } + + public void setPad(Pad pad) { + this.pad = pad; + } + + public static void setProject(Project project) { + PadDragListener.project = project; + } + +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..c55b73efa8069e3c0d59c7731bcd74d8e5dbdf02 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewController.java @@ -0,0 +1,345 @@ +package de.tobias.playpad.viewcontroller.pad; + +import java.io.File; +import java.nio.file.Path; +import java.util.Set; + +import de.tobias.playpad.PlayPadPlugin; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.TimeMode; +import de.tobias.playpad.pad.conntent.Durationable; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.pad.conntent.PadContentConnect; +import de.tobias.playpad.pad.conntent.PadContentRegistry; +import de.tobias.playpad.pad.conntent.UnkownPadContentException; +import de.tobias.playpad.pad.listener.PadContentListener; +import de.tobias.playpad.pad.listener.PadDurationListener; +import de.tobias.playpad.pad.listener.PadPositionListener; +import de.tobias.playpad.pad.listener.PadStatusListener; +import de.tobias.playpad.pad.view.IPadViewController; +import de.tobias.playpad.view.FileDragOptionView; +import de.tobias.playpad.view.PadView; +import de.tobias.playpad.viewcontroller.IPadView; +import de.tobias.playpad.viewcontroller.option.pad.PadSettingsViewController; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.util.FileUtils; +import de.tobias.utils.util.Localization; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.Node; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Stage; +import javafx.util.Duration; + +public class PadViewController implements EventHandler<ActionEvent>, IPadViewController { + + private static final String DURATION_FORMAT = "%d:%02d"; + private static final String OPEN_FOLDER = "openFolder"; + + private PadView view; + private Pad pad; + + private PadStatusListener padStatusListener; + private PadContentListener padContentListener; + private PadDurationListener padDurationListener; + private PadPositionListener padPositionListener; + + private PadDragListener padDragListener; + + public PadViewController() { + view = new PadView(this); + + padStatusListener = new PadStatusListener(this); + padContentListener = new PadContentListener(this); + padDurationListener = new PadDurationListener(this); + padPositionListener = new PadPositionListener(this); + } + + @Override + public IPadView getParent() { + return view; + } + + @Override + public void handle(ActionEvent event) { + if (event.getSource() == view.getPlayButton()) { + onPlay(); + } else if (event.getSource() == view.getPauseButton()) { + onPause(); + } else if (event.getSource() == view.getStopButton()) { + onStop(); + } else if (event.getSource() == view.getNewButton()) { + onNew(event); + } else if (event.getSource() == view.getSettingsButton()) { + onSettings(); + } + } + + private void onPlay() { + if (pad.getContent() != null) { + pad.setStatus(PadStatus.PLAY); + } + } + + private void onPause() { + if (pad.getContent() != null) { + pad.setStatus(PadStatus.PAUSE); + } + } + + private void onStop() { + if (pad.getContent() != null) { + pad.setStatus(PadStatus.STOP); + } + } + + private void onNew(ActionEvent event) { + FileChooser chooser = new FileChooser(); + + // File Extension + ExtensionFilter extensionFilter = new ExtensionFilter(Localization.getString(Strings.File_Filter_Media), + PadContentRegistry.getSupportedFileTypes()); + chooser.getExtensionFilters().add(extensionFilter); + + // Last Folder + Object openFolder = ApplicationUtils.getApplication().getUserDefaults().getData(OPEN_FOLDER); + if (openFolder != null) { + File folder = new File(openFolder.toString()); + chooser.setInitialDirectory(folder); + } + + File file = chooser.showOpenDialog(((Node) event.getTarget()).getScene().getWindow()); + if (file != null) { + Path path = file.toPath(); + + try { + Set<PadContentConnect> connects = PadContentRegistry.getPadContentConnectsForFile(file.toPath()); + if (!connects.isEmpty()) { + if (connects.size() > 1) { + FileDragOptionView hud = new FileDragOptionView(view); + hud.showDropOptions(connects, connect -> + { + if (connect != null) { + setNewPadContent(file, path, connect); + hud.hide(); + } + }); + } else { + PadContentConnect connect = connects.iterator().next(); + setNewPadContent(file, path, connect); + } + } + } catch (UnkownPadContentException e) { + e.printStackTrace(); + } + + ApplicationUtils.getApplication().getUserDefaults().setData(OPEN_FOLDER, path.getParent().toString()); + } + } + + private void setNewPadContent(File file, Path path, PadContentConnect connect) { + PadContent content = pad.getContent(); + if (pad.getContent() == null || !pad.getContent().getType().equals(connect.getType())) { + content = connect.newInstance(pad); + this.pad.setContent(content); + } + + content.handlePath(file.toPath()); + this.pad.setName(FileUtils.getFilenameWithoutExtention(path.getFileName())); + } + + private void onSettings() { + Stage owner = PlayPadPlugin.getImplementation().getMainViewController().getStage(); + PadSettingsViewController controller = new PadSettingsViewController(pad, owner); + controller.getStage().setOnHidden(ev -> + { + view.setTriggerLabelActive(pad.hasTriggerItems()); + }); + controller.getStage().show(); + } + + @Override + public void unconnectPad() { + view.getIndexLabel().setText(""); + view.clearPreviewContent(); + view.getTimeLabel().setText(""); + + view.setTriggerLabelActive(false); + + view.getLoopLabel().visibleProperty().unbind(); + + if (pad != null) { + pad.contentProperty().removeListener(padContentListener); + pad.statusProperty().removeListener(padStatusListener); + + if (pad.getContent() instanceof Durationable) { + Durationable durationable = (Durationable) pad.getContent(); + durationable.durationProperty().removeListener(padDurationListener); + durationable.positionProperty().removeListener(padPositionListener); + } + pad.setController(null); + padDragListener = null; + + // GUI Cleaning + getPadPositionListener().stopWaning(); + view.removeStyleClasses(pad); + } + this.pad = null; + } + + @Override + public Pad getPad() { + return pad; + } + + @Override + public void setPad(Pad pad) { + unconnectPad(); + this.pad = pad; + + view.setPreviewContent(pad); + view.addStyleClasses(pad); + + connectPad(); + } + + @Override + public void connectPad() { + pad.setController(this); + + try { + view.getIndexLabel().setText(String.valueOf(pad.getIndexReadable())); + view.getLoopLabel().visibleProperty().bind(pad.loopProperty()); + + view.setTriggerLabelActive(pad.hasTriggerItems()); + + // Update Listener + padContentListener.setPad(pad); + padPositionListener.setPad(pad); + + // Pad Content Chnage + pad.contentProperty().addListener(padContentListener); + // Pad Status Change + pad.statusProperty().addListener(padStatusListener); + + // First Listener call with new data + padContentListener.changed(null, null, pad.getContent()); // Add Duration listener + padStatusListener.changed(null, null, pad.getStatus()); + + padDragListener = new PadDragListener(pad, view); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void updateTimeLabel() { + if (pad.getContent() != null && pad.getStatus() != PadStatus.EMPTY && pad.getStatus() != PadStatus.ERROR) { + if (pad.getContent() instanceof Durationable) { + Durationable durationable = (Durationable) pad.getContent(); + + Duration duration = durationable.getDuration(); + Duration position = durationable.getPosition(); + + if (duration != null) { + // Nur Gesamtzeit anzeigen + if (pad.getStatus() == PadStatus.READY || position == null) { + String time = durationToString(duration); + view.getTimeLabel().setText(time); + view.getPlayBar().setProgress(0); + } else { + // Play/Gesamtzeit anzeigen + TimeMode timeMode = pad.getTimeMode(); + + if (timeMode == TimeMode.REST) { + Duration leftTime = duration.subtract(position); + view.getTimeLabel().setText("- " + durationToString(leftTime)); + } else if (timeMode == TimeMode.PLAYED) { + view.getTimeLabel().setText(durationToString(position)); + } else if (timeMode == TimeMode.BOTH) { + String time = durationToString(position); + String totalTime = durationToString(duration); + view.getTimeLabel().setText(time + "/" + totalTime); + } + } + } + return; + } + } + view.getPlayBar().setProgress(0); + view.getTimeLabel().setText(""); + } + + public String durationToString(Duration value) { + if (value != null) { + int secounds = (int) ((value.toMillis() / 1000) % 60); + int minutes = (int) ((value.toMillis() / (1000 * 60)) % 60); + String time = String.format(DURATION_FORMAT, minutes, secounds); + return time; + } else { + return null; + } + } + + public void updateButtonDisable() { + if (pad.getContent() != null) { + if (pad.getStatus() == PadStatus.PLAY) { + view.getPlayButton().setDisable(true); + view.getPauseButton().setDisable(false); + view.getStopButton().setDisable(false); + view.getNewButton().setDisable(true); + view.getSettingsButton().setDisable(false); + } else if (pad.getStatus() == PadStatus.PAUSE) { + view.getPlayButton().setDisable(false); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(false); + view.getNewButton().setDisable(true); + view.getSettingsButton().setDisable(false); + } else if (pad.getStatus() == PadStatus.STOP) { + view.getPlayButton().setDisable(false); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + view.getNewButton().setDisable(true); + view.getSettingsButton().setDisable(false); + } else if (pad.getStatus() == PadStatus.READY) { + view.getPlayButton().setDisable(false); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + view.getNewButton().setDisable(false); + view.getSettingsButton().setDisable(false); + } + } else if (pad.getStatus() == PadStatus.EMPTY || pad.getStatus() == PadStatus.ERROR || pad.getContent() == null + || !pad.getContent().isPadLoaded()) { + view.getPlayButton().setDisable(true); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + view.getNewButton().setDisable(false); + view.getSettingsButton().setDisable(false); + } + } + + @Override + public void showDnDLayout(boolean b) { + view.pseudoClassState(PseudoClasses.DRAG_CLASS, b); + } + + // getter for listener + public PadDurationListener getPadDurationListener() { + return padDurationListener; + } + + public PadStatusListener getPadStatusListener() { + return padStatusListener; + } + + public PadPositionListener getPadPositionListener() { + return padPositionListener; + } + + public PadDragListener getPadDragListener() { + return padDragListener; + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewControllerOld.java b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewControllerOld.java new file mode 100644 index 0000000000000000000000000000000000000000..4fce7090ec092d55de01ac19a7e3021ba4657033 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PadViewControllerOld.java @@ -0,0 +1,755 @@ +package de.tobias.playpad.viewcontroller.pad; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.controlsfx.dialog.ExceptionDialog; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.PseudoClasses; +import de.tobias.playpad.Strings; +import de.tobias.playpad.action.mapper.listener.MidiHandler; +import de.tobias.playpad.audio.AudioHandler; +import de.tobias.playpad.audio.AudioRegistry; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Pad.PadStatus; +import de.tobias.playpad.pad.Pad.TimeMode; +import de.tobias.playpad.model.PadException; +import de.tobias.playpad.model.PadException.PadExceptionType; +import de.tobias.playpad.model.Project; +import de.tobias.playpad.plugin.ExtensionHandler; +import de.tobias.playpad.plugin.PadListener; +import de.tobias.playpad.plugin.PlayPadPlugin; +import de.tobias.playpad.plugin.viewcontroller.IPadViewController; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.view.AudioPadView; +import de.tobias.playpad.viewcontroller.PadSettingsViewController; +import de.tobias.utils.application.ApplicationUtils; +import de.tobias.utils.ui.NotificationHandler; +import de.tobias.utils.ui.Refreshable; +import de.tobias.utils.util.Localization; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; +import javafx.stage.Stage; +import javafx.util.Duration; + +public class PadViewController implements IPadViewController, EventHandler<ActionEvent>, ChangeListener<Duration> { + + private static final String DURATION_FORMAT = "%d:%02d"; + + private static final String OPEN_FOLDER = "openFolder"; + + public static ObservableList<PadException> exceptions = FXCollections.observableArrayList(); + + private AudioPadView view; + + protected Pad pad; + protected int page; + + // Listener + private ChangeListener<Duration> totalDurationListener; + private ChangeListener<AudioHandler> audioHandlerListener; + private ChangeListener<PadStatus> stateListener; + private ChangeListener<Boolean> audioLoadedListener; + private ChangeListener<String> titleListener; + private ChangeListener<PadException> exceptionListener; + private PlayDurationEventHandler durationEventHandler; + + // Drag and Drop + private PadDragHandler<?> dragAndDrop; + + // Refresh in Window + private Refreshable refreshable; + private NotificationHandler notificationHandler; + + private MidiHandler handler; + protected int midiKeyPressedForPlay; + + // Window Referenz + private PadSettingsViewController padSettingsViewController; + + private static int playedPlayers; + + private synchronized static void addPlayer() { + playedPlayers++; + } + + private synchronized static void removePlayer() { + if (playedPlayers > 0) { + playedPlayers--; + } + } + + public synchronized static int getPlayedPlayers() { + return playedPlayers; + } + + public <T extends Refreshable & NotificationHandler> PadViewController(T t, Project project, MidiHandler handler) { + view = new AudioPadView(this); + dragAndDrop = new PadDragHandler<T>(pad, view, t); + + this.refreshable = t; + this.notificationHandler = t; + this.handler = handler; + + view.getErrorLabel().setOnMouseClicked(event -> + { + showError(); + }); + } + + public Pad getPad() { + return pad; + } + + public void setPad(Pad pad, int page) { + if (this.pad != null) { + this.pad.setController(null); + cleanUp(); + } + + this.pad = pad; + this.page = page; + this.pad.setController(this); + this.dragAndDrop.setPad(pad); + + view.addDefaultButton(); + preparePad(); + + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) { + try { + listener.onPadVisible(pad); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private void preparePad() { + // Display Pad Once + view.getIndexLabel().setText(String.valueOf(pad.getIndex() + 1)); + + view.getTimeLabel().setText(""); + // Binding und Listener + totalDurationListener = (a, b, c) -> + { + if (c != null) { + showPadDuration(); + } else { + Platform.runLater(() -> view.getTimeLabel().setText("")); + } + }; + + stateListener = (a, b, c) -> stateChange(b, c); + + audioLoadedListener = (a, b, c) -> + { + // TODO Init MIDI Page + }; + + audioHandlerListener = (a, b, c) -> + { + b.durationProperty(pad).removeListener(totalDurationListener); + c.durationProperty(pad).addListener(totalDurationListener); + + b.loadedProperty().removeListener(audioLoadedListener); + c.loadedProperty().addListener(audioLoadedListener); + }; + + titleListener = (a, b, c) -> + { + view.getNameLabel().setText(c); + }; + + exceptionListener = (a, b, c) -> + { + if (c != null && !exceptions.contains(c)) { + view.setErrorLabelActive(true); + exceptions.add(c); + } else { + view.setErrorLabelActive(false); + exceptions.remove(b); + } + }; + + // AudioHandler Listener + pad.audioHandlerProperty().addListener(audioHandlerListener); + + pad.titleProperty().addListener(titleListener); + view.getNameLabel().setText(pad.getTitle()); + + // Listener für Gesamtzeit (Wenn neues Media File oder so) + pad.getAudioHandler().durationProperty(pad).addListener(totalDurationListener); + + // Time label Clickable für Time Display Art + view.getTimeLabel().setOnMouseClicked(event -> + { + TimeMode timeMode = Profile.currentProfile().getProfileSettings().getPlayerTimeDisplayMode(); + if (pad.isCustomTimeMode()) { + timeMode = pad.getTimeMode().get(); + } + + if (timeMode == TimeMode.PLAYED) { + pad.setTimeMode(TimeMode.REST); + } else if (timeMode == TimeMode.REST) { + pad.setTimeMode(TimeMode.BOTH); + } else if (timeMode == TimeMode.BOTH) { + pad.setTimeMode(TimeMode.PLAYED); + } + }); + + view.setLoopLabelActive(pad.isLoop()); + + // Für LaunchPad Feedback + pad.getAudioHandler().loadedProperty().addListener(audioLoadedListener); + + // State des Pad -> UI Änderungen (wie Progressbar oder Button) + pad.statusProperty().addListener(stateListener); + + // Init + stateChange(null, pad.getStatus()); + if (pad.getAudioHandler().durationProperty(pad).isNotNull().get()) { + showPadDuration(); + } + + // Errors + pad.lastExceptionProperty().addListener(exceptionListener); + view.setErrorLabelActive(pad.getLastException() != null); + if (pad.getLastException() != null && !exceptions.contains(pad.getLastException())) { + exceptions.add(pad.getLastException()); + } + + // CSS + view.getStyleClass().addAll("pad", "pad" + pad.getIndex()); + + view.getIndexLabel().getStyleClass().addAll("pad-index", "pad" + pad.getIndex() + "-index", "pad-info", + "pad" + pad.getIndex() + "-info"); + view.getTimeLabel().getStyleClass().addAll("pad-time", "pad" + pad.getIndex() + "-time", "pad-info", "pad" + pad.getIndex() + "-info"); + view.getNameLabel().getStyleClass().addAll("pad-title", "pad" + pad.getIndex() + "-title"); + + view.getPlayBar().getStyleClass().addAll("pad-playbar", "pad" + pad.getIndex() + "-playbar"); + + view.getPlayButton().getStyleClass().addAll("pad-button", "pad-playbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-playbutton"); + view.getPauseButton().getStyleClass().addAll("pad-button", "pad-pausebutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-pausebutton"); + view.getStopButton().getStyleClass().addAll("pad-button", "pad-stopbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-stopbutton"); + view.getNewButton().getStyleClass().addAll("pad-button", "pad-newbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-newbutton"); + view.getSettingsButton().getStyleClass().addAll("pad-button", "pad-settingsbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-settingsbutton"); + + view.getPlayButton().getGraphic().getStyleClass().addAll("pad-button-icon", "pad-playbutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + view.getPauseButton().getGraphic().getStyleClass().addAll("pad-button-icon", "pad-pausebutton-icon", + "pad" + pad.getIndex() + "-button-icon", "padv-playbutton--icon"); + view.getStopButton().getGraphic().getStyleClass().addAll("pad-button-icon", "pad-stopbutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + view.getNewButton().getGraphic().getStyleClass().addAll("pad-button-icon", "pad-newbutton-icon", "pad" + pad.getIndex() + "-button-icon", + "pad" + pad.getIndex() + "-playbutton-icon"); + view.getSettingsButton().getGraphic().getStyleClass().addAll("pad-button-icon", "pad-deletebutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + + view.getButtonBox().getStyleClass().add("pad-button-box"); + view.getRoot().getStyleClass().add("pad-root"); + } + + /* + * Button Action + */ + @Override + public void handle(ActionEvent event) { + if (event.getSource() == view.getPlayButton()) { + pad.setStatus(PadStatus.PLAY); + } else if (event.getSource() == view.getPauseButton()) { + pad.setStatus(PadStatus.PAUSE); + } else if (event.getSource() == view.getStopButton()) { + pad.setStatus(PadStatus.STOP); + } else if (event.getSource() == view.getSettingsButton()) { + openSettings(); + } else if (event.getSource() == view.getNewButton()) { + if (getPlayedPlayers() > 0) { + notificationHandler.notify(Localization.getString(Strings.Error_Pad_Livemode), PlayPadMain.notificationDisplayTimeMillis); + } else { + chooseFile(event); + } + } + } + + private void chooseFile(ActionEvent event) { + FileChooser chooser = new FileChooser(); + + // File Extension + ExtensionFilter extensionFilter = new ExtensionFilter(Localization.getString(Strings.File_Filter_Media), + AudioRegistry.geAudioType().getSupportedTypes()); + chooser.getExtensionFilters().add(extensionFilter); + for (ExtensionHandler handler : PlayPadPlugin.getImplementation().getExtensionsHandler()) { + chooser.getExtensionFilters().add(new ExtensionFilter(handler.getName(), handler.getExtensions())); + } + + // Last Folder + Object openFolder = ApplicationUtils.getApplication().getUserDefaults().getData(OPEN_FOLDER); + if (openFolder != null) { + File folder = new File(openFolder.toString()); + chooser.setInitialDirectory(folder); + } + + File file = chooser.showOpenDialog(((Node) event.getTarget()).getScene().getWindow()); + if (file != null) { + Path path = file.toPath(); + ExtensionFilter filter = chooser.getSelectedExtensionFilter(); + + for (ExtensionHandler handler : PlayPadPlugin.getImplementation().getExtensionsHandler()) { + if (filter.getDescription().equals(handler.getName())) { + handler.handle(path, pad); + return; + } + } + + pad.setPath(path); + ApplicationUtils.getApplication().getUserDefaults().setData(OPEN_FOLDER, path.getParent().toString()); + } + } + + private void openSettings() { + if (padSettingsViewController == null) { + padSettingsViewController = new PadSettingsViewController(pad, this, view.getScene().getWindow()); + padSettingsViewController.getStage().showAndWait(); + refreshable.updateData(); + + padSettingsViewController = null; + } else if (padSettingsViewController.getStage().isShowing()) { + padSettingsViewController.getStage().toFront(); + } + } + + @Override + public void changed(ObservableValue<? extends Duration> arg0, Duration arg1, Duration newValue) { + // Progressbar (Prozente) + if (pad != null) { + double value = newValue.toMillis() / pad.getAudioHandler().getDuration(pad).toMillis(); + view.getPlayBar().setProgress(value); + + // Label (Restlaufzeit) + TimeMode timeMode = Profile.currentProfile().getProfileSettings().getPlayerTimeDisplayMode(); + if (pad.isCustomTimeMode()) { + timeMode = pad.getTimeMode().get(); + } + if (timeMode == TimeMode.REST) { + Duration leftTime = pad.getAudioHandler().getDuration(pad).subtract(newValue); + view.getTimeLabel().setText("- " + durationToString(leftTime)); + } else if (timeMode == TimeMode.PLAYED) { + view.getTimeLabel().setText(durationToString(newValue)); + } else if (timeMode == TimeMode.BOTH) { + String time = durationToString(newValue); + String totalTime = durationToString(pad.getAudioHandler().getDuration(pad)); + + view.getTimeLabel().setText(time + "/" + totalTime); + } + } + } + + private String durationToString(Duration value) { + int secounds = (int) ((value.toMillis() / 1000) % 60); + int minutes = (int) ((value.toMillis() / (1000 * 60)) % 60); + String time = String.format(DURATION_FORMAT, minutes, secounds); + return time; + } + + private void showPadDuration() { + Duration c = pad.getAudioHandler().getDuration(pad); + if (c != null) { + Platform.runLater(() -> view.getTimeLabel().setText(durationToString(c))); + } else { + Platform.runLater(() -> view.getTimeLabel().setText("")); + } + } + + // GUI Veränderung und Pad Aktionen wenn sich der Sate durch die Buttons oder durch MIDI ändert + public void stateChange(PadStatus oldState, PadStatus newState) { + Profile profile = Profile.currentProfile(); + if (pad.isCustomLayout()) { + pad.getLayout(profile.getProfileSettings().getLayoutType()).ifPresent(layout -> layout.updatePadView(this, oldState, newState)); + } else { + profile.currentLayout().updatePadView(this, oldState, newState); + } + + switch (newState) { + case PLAY: + playState(oldState, newState); + break; + case PAUSE: + pauseState(oldState, newState); + break; + case STOP: + stopState(oldState, newState); + break; + case READY: + readyState(); + break; + case EMPTY: + emptyState(); + break; + } + } + + private void playState(PadStatus oldState, PadStatus newState) { + // PadListener + boolean ignoreNoMedia = false; + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) { + try { + if (listener.ignoreNoMedia(pad)) { + ignoreNoMedia = true; + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (!ignoreNoMedia) { + if (!pad.getAudioHandler().isMediaLoaded(pad)) { + pad.loadMedia(); // Try to Load wenn nicht geladen + if (!pad.getAudioHandler().isMediaLoaded(pad)) { + String file = pad.getFile(); + if (file != null) + file = file.replace("%20", " "); + notificationHandler + .showError(Localization.getString(Strings.Error_Pad_BaseName + PadExceptionType.FILE_NOT_FOUND.toString(), file)); + pad.setState(PadStatus.READY); + return; + } + } + } + + // PadListener + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) + try { + if (!listener.onPlay(pad)) + return; + } catch (Exception e) { + e.printStackTrace(); + } + + // Bei Pause werden die Listener nicht entfernt, bei Stop schon. bei Stop wird der Listener = null. Nur dann muss er neu + // hinzugefügt werden + if (durationEventHandler == null && pad.currentDurationProperty() != null) { + durationEventHandler = new PlayDurationEventHandler(this); + pad.currentDurationProperty().addListener(durationEventHandler); + pad.currentDurationProperty().addListener(this); + } + if (durationEventHandler != null) + durationEventHandler.send = false; + + // midi Feedback + // TODO MIDI Send Feedback + // try { + // } catch (MidiUnavailableException | InvalidMidiDataException e) { + // notificationHandler.showError(Localization.getString(Strings.Error_Midi_Send, e.getLocalizedMessage())); + // e.printStackTrace(); + // } + + if (pad.getAudioHandler().isMediaLoaded(pad)) + pad.play(); + addPlayer(); + + Platform.runLater(() -> + { + view.getPlayButton().setDisable(true); + view.getPauseButton().setDisable(false); + view.getStopButton().setDisable(false); + view.pseudoClassState(PseudoClasses.PLAY_CALSS, true); + }); + } + + private void pauseState(PadStatus oldState, PadStatus newState) { + pad.pause(true, () -> + { + // Bei Fade Out Ende löschen + view.pseudoClassState(PseudoClasses.FADE_CLASS, false); + removePlayer(); + durationEventHandler.stopWaning(); + }); + + Platform.runLater(() -> + { + view.getPlayButton().setDisable(false); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(false); + + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + + // Fade Out Style hintufügen + if (!pad.isEof() && (pad.isCustomFade() && pad.getFade().get().getFadeOut().toMillis() > 0 + || !pad.isCustomFade() && Profile.currentProfile().getProfileSettings().getFade().getFadeOut().toSeconds() > 0)) + view.pseudoClassState(PseudoClasses.FADE_CLASS, true); + }); + sendFeedback(oldState, newState); + } + + private void stopState(PadStatus oldState, PadStatus newState) { + if (pad.currentDurationProperty() != null) { + pad.currentDurationProperty().removeListener(this); + if (durationEventHandler != null) + pad.currentDurationProperty().removeListener(durationEventHandler); + } + + // PadListener + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) + try { + listener.onStop(pad); + } catch (Exception e) { + e.printStackTrace(); + } + + // TODO Init MIDI Page + + boolean fadeListener = true; + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) { + if (!listener.allowFade(pad)) { + fadeListener = false; + } + } + + final boolean fade = fadeListener; + + // UI Clean in State READY + Platform.runLater(() -> + { + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + + if (durationEventHandler != null) + durationEventHandler.stopWaning(); + durationEventHandler = null; + + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + + if (oldState != PadStatus.PAUSE && fade) { + if (!pad.isEof() && (pad.isCustomFade() && pad.getFade().get().getFadeOut().toMillis() > 0 + || !pad.isCustomFade() && Profile.currentProfile().getProfileSettings().getFade().getFadeOut().toSeconds() > 0)) { + view.pseudoClassState(PseudoClasses.FADE_CLASS, true); + } + } + }); + + pad.stop(oldState != PadStatus.PAUSE && fade, () -> + { + // Bei Ende von Fade Out wird CSS removed + view.pseudoClassState(PseudoClasses.FADE_CLASS, false); + }); + + sendFeedback(oldState, newState); + } + + private void readyState() { + // Clean UI vom Play + Platform.runLater(() -> + { + view.getPlayBar().setProgress(0.0); + showPadDuration(); + + view.getPlayButton().setDisable(false); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + view.pseudoClassState(PseudoClasses.FADE_CLASS, false); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + + // PadListener + for (PadListener listener : PlayPadPlugin.getImplementation().getPadListener()) + try { + listener.onReady(pad); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + removePlayer(); + } + + private void emptyState() { + view.getPlayButton().setDisable(true); + view.getPauseButton().setDisable(true); + view.getStopButton().setDisable(true); + } + + public void sendFeedback(PadStatus oldState, PadStatus newState) { + // TODO MIDI Send Feedback + } + + public void cleanUp() { + if (pad != null) { + // Wenn Play oder Pause dann erst Stop, bevor alles Aufgeräumt wird + if (pad.getStatus() == PadStatus.PLAY || pad.getStatus() == PadStatus.PAUSE) + pad.setStatus(PadStatus.STOP); + + pad.stop(false, null); + + // Listener für Gesamtzeit weg + // State des Pad -> UI Änderungen (wie Progressbar oder Button) + pad.getAudioHandler().durationProperty(pad).removeListener(totalDurationListener); + pad.stateProperty().removeListener(stateListener); + pad.getAudioHandler().loadedProperty().removeListener(audioLoadedListener); + pad.titleProperty().removeListener(titleListener); + pad.lastExceptionProperty().removeListener(exceptionListener); + pad.audioHandlerProperty().removeListener(audioHandlerListener); + + // view.getNameLabel().textProperty().unbind(); // Clear Title Label + view.getTimeLabel().setText(""); // Clear Time Label + view.getPlayBar().setProgress(0); // Zeit Leiste + view.setErrorLabelActive(false); // Error Weg + + view.getStyleClass().removeAll("pad", "pad" + pad.getIndex()); + + view.pseudoClassState(PseudoClasses.PLAY_CALSS, false); + view.pseudoClassState(PseudoClasses.FADE_CLASS, false); + view.pseudoClassState(PseudoClasses.WARN_CLASS, false); + + view.getIndexLabel().getStyleClass().removeAll("pad-index", "pad" + pad.getIndex() + "-index", "pad-info", + "pad" + pad.getIndex() + "-info"); + view.getTimeLabel().getStyleClass().removeAll("pad-time", "pad" + pad.getIndex() + "-time", "pad-info", + "pad" + pad.getIndex() + "-info"); + view.getNameLabel().getStyleClass().removeAll("pad-title", "pad" + pad.getIndex() + "-title"); + view.getPlayBar().getStyleClass().removeAll("pad-playbar", "pad" + pad.getIndex() + "-playbar"); + + view.getPlayButton().getStyleClass().removeAll("pad-button", "pad-playbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-playbutton"); + view.getPauseButton().getStyleClass().removeAll("pad-button", "pad-pausebutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-pausebutton"); + view.getStopButton().getStyleClass().removeAll("pad-button", "pad-stopbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-stopbutton"); + view.getNewButton().getStyleClass().removeAll("pad-button", "pad-newbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-newbutton"); + view.getSettingsButton().getStyleClass().removeAll("pad-button", "pad-settingsbutton", "pad" + pad.getIndex() + "-button", + "pad" + pad.getIndex() + "-settingsbutton"); + + view.getPlayButton().getGraphic().getStyleClass().removeAll("pad-button-icon", "pad-playbutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + view.getPauseButton().getGraphic().getStyleClass().removeAll("pad-button-icon", "pad-pausebutton-icon", + "pad" + pad.getIndex() + "-button-icon", "padv-playbutton--icon"); + view.getStopButton().getGraphic().getStyleClass().removeAll("pad-button-icon", "pad-stopbutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + view.getNewButton().getGraphic().getStyleClass().removeAll("pad-button-icon", "pad-newbutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + view.getSettingsButton().getGraphic().getStyleClass().removeAll("pad-button-icon", "pad-deletebutton-icon", + "pad" + pad.getIndex() + "-button-icon", "pad" + pad.getIndex() + "-playbutton-icon"); + + view.getButtonBox().getStyleClass().removeAll("pad-button-box"); + view.getRoot().getStyleClass().removeAll("pad-root"); + } + } + + public AudioPadView getView() { + return view; + } + + // TODO ErrorHandling + private void showError() { + PadException lastException = pad.getLastException(); + + try { + ExceptionDialog dialog = new ExceptionDialog(lastException); + dialog.setHeaderText(Localization.getString(Strings.Error_Pad_BaseName + lastException.getType().name(), pad.getPath())); + + if (PlayPadMain.stageIcon.isPresent()) { + Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); + stage.getIcons().add(PlayPadMain.stageIcon.get()); + } + + dialog.setTitle(Localization.getString(Strings.UI_Dialog_Error_Title)); + dialog.initOwner(refreshable.getStage()); + dialog.showAndWait(); + + view.setErrorLabelActive(false); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Fügt einen Button zum Pad hinzu + * + * @param button + * + * @since 2.0.2 + */ + public void addButton(Button button, ButtonPosition buttonPosition) { + if (buttonPosition == ButtonPosition.TOP) { + if (!view.getButtonBox().getChildren().contains(button)) { + view.getInfoBox().getChildren().add(button); + } + } else if (buttonPosition == ButtonPosition.BOTTOM) { + if (!view.getButtonBox().getChildren().contains(button)) { + view.getButtonBox().getChildren().add(button); + } + } + } + + /** + * Fügt einen Button zum Pad hinzu + * + * @param button + * Button + * @param index + * Index + * + * @since 2.0.2 + */ + public void addNode(Node button, int index, ButtonPosition buttonPosition) { + if (buttonPosition == ButtonPosition.TOP) { + if (!view.getButtonBox().getChildren().contains(button)) { + view.getInfoBox().getChildren().add(index, button); + } + } else if (buttonPosition == ButtonPosition.BOTTOM) { + if (!view.getButtonBox().getChildren().contains(button)) { + view.getButtonBox().getChildren().add(index, button); + } + } + } + + /** + * Löscht einen Button vom Pad + * + * @param button + * + * @since 2.0.2 + */ + public void removeNode(Node button) { + if (view.getButtonBox().getChildren().contains(button)) { + view.getButtonBox().getChildren().remove(button); + } else if (view.getInfoBox().getChildren().contains(button)) { + view.getInfoBox().getChildren().remove(button); + } + } + + public List<Node> getCustomNodes() { + List<Node> buttons = new ArrayList<>(); + for (Node node : view.getButtonBox().getChildren()) { + if (node != view.getPlayButton() || node != view.getPauseButton() || node != view.getStopButton() || node != view.getNewButton() + || node != view.getSettingsButton()) { + buttons.add((Button) node); + } + } + return buttons; + } + + public void showDnDLayout(boolean show) { + view.pseudoClassState(PseudoClasses.DRAG_CLASS, show); + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PlayDurationEventHandler.java b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PlayDurationEventHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..d603e65dbed0e8c5261784ffc4624391c1ba859f --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/pad/PlayDurationEventHandler.java @@ -0,0 +1,95 @@ +package de.tobias.playpad.viewcontroller.pad; + +import de.tobias.playpad.midi.Midi; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.pad.Warning; +import de.tobias.playpad.settings.Profile; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.util.Duration; + +// TODO Renew class +class PlayDurationEventHandler implements ChangeListener<Duration>, Runnable { + + /** + * + */ + private final PadViewController padViewController; + + /** + * @param padViewController + */ + PlayDurationEventHandler(PadViewController padViewController) { + this.padViewController = padViewController; + } + + boolean send = false; + + private Thread warningThread; + + @Override + public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { + if (!send) { + if (padViewController != null && padViewController.pad != null && !this.padViewController.pad.isLoop()) { + Duration rest = this.padViewController.pad.getAudioHandler().getDuration(this.padViewController.pad).subtract(newValue); + double seconds = rest.toSeconds(); + + Midi midi = Midi.getInstance(); + + if (this.padViewController.midiKeyPressedForPlay != -1) { + if (this.padViewController.pad.isCustomWarning()) { + if (this.padViewController.pad.getWarningFeedback().get().getTime().toSeconds() > seconds) { + startWarningThread(); + + if (midi.getMidiDevice().isPresent()) { + // TODO MIDI Send Feedback + } + send = true; + } + } else { + if (Profile.currentProfile().getProfileSettings().getWarningFeedback().getTime().toSeconds() > seconds) { + startWarningThread(); + + if (midi.getMidiDevice().isPresent()) { + // TODO MIDI Send Feedback + } + send = true; + } + } + } + } + } + } + + /* + * EoF GUI Flash + */ + @Override + public void run() { + Pad pad = padViewController.getPad(); + + Profile currentProfile = Profile.currentProfile(); + Warning warning = pad.getWarningFeedback().orElseGet(() -> currentProfile.getProfileSettings().getWarningFeedback()); + if (pad.isCustomLayout()) { + pad.currentLayout().ifPresent(layout -> layout.handleWarning(padViewController, warning)); + } else { + currentProfile.currentLayout().handleWarning(padViewController, warning); + } + } + + protected void startWarningThread() { + if (warningThread != null) { + warningThread.interrupt(); + } + warningThread = new Thread(this); + warningThread.start(); + } + + protected void stopWaning() { + if (warningThread != null) { + warningThread.interrupt(); + padViewController.getView().setStyle(""); + warningThread = null; + } + } +} \ No newline at end of file diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/settings/FadeViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/settings/FadeViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..2a4ee9720e830b10eedb994e8534521a945c4ec2 --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/settings/FadeViewController.java @@ -0,0 +1,74 @@ +package de.tobias.playpad.viewcontroller.settings; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Fade; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.util.Duration; + +public class FadeViewController extends ContentViewController { + + @FXML private Slider fadeInSlider; + @FXML private Slider fadeOutSlider; + @FXML private Label fadeInLabel; + @FXML private Label fadeOutLabel; + + @FXML private CheckBox fadeInStartCheckBox; + @FXML private CheckBox fadeInPauseCheckBox; + @FXML private CheckBox fadeOutPauseCheckBox; + @FXML private CheckBox fadeOutStopCheckBox; + + private Fade fade; + + public FadeViewController() { + super("fadeView", "de/tobias/playpad/assets/settings/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public void init() { + fadeInSlider.valueProperty().addListener((a, b, c) -> + { + Duration seconds = Duration.seconds(c.doubleValue()); + double displayedTime = Math.round(seconds.toSeconds() * 10) / 10.0; + fadeInLabel.setText(Localization.getString(Strings.Standard_Time_Seconds, displayedTime)); + fade.setFadeIn(seconds); + }); + + fadeOutSlider.valueProperty().addListener((a, b, c) -> + { + Duration seconds = Duration.seconds(c.doubleValue()); + double displayedTime = Math.round(seconds.toSeconds() * 10) / 10.0; + fadeOutLabel.setText(Localization.getString(Strings.Standard_Time_Seconds, displayedTime)); + fade.setFadeOut(seconds); + }); + + fadeInStartCheckBox.selectedProperty().addListener((a, b, c) -> fade.setFadeInStart(c)); + fadeInPauseCheckBox.selectedProperty().addListener((a, b, c) -> fade.setFadeInPause(c)); + fadeOutPauseCheckBox.selectedProperty().addListener((a, b, c) -> fade.setFadeOutPause(c)); + fadeOutStopCheckBox.selectedProperty().addListener((a, b, c) -> fade.setFadeOutStop(c)); + } + + public void setFade(Fade fade) { + this.fade = fade; + + if (fade != null) { + fadeInSlider.setValue(fade.getFadeIn().toSeconds()); + double displayedInTime = Math.round(fade.getFadeIn().toSeconds() * 10) / 10.0; + fadeInLabel.setText(Localization.getString(Strings.Standard_Time_Seconds, displayedInTime)); + + fadeOutSlider.setValue(fade.getFadeOut().toSeconds()); + double displayedOutTime = Math.round(fade.getFadeOut().toSeconds() * 10) / 10.0; + fadeOutLabel.setText(Localization.getString(Strings.Standard_Time_Seconds, displayedOutTime)); + + fadeInStartCheckBox.setSelected(fade.isFadeInStart()); + fadeInPauseCheckBox.setSelected(fade.isFadeInPause()); + fadeOutPauseCheckBox.setSelected(fade.isFadeOutPause()); + fadeOutStopCheckBox.setSelected(fade.isFadeOutStop()); + } + } +} diff --git a/PlayWall/src/de/tobias/playpad/viewcontroller/settings/WarningFeedbackViewController.java b/PlayWall/src/de/tobias/playpad/viewcontroller/settings/WarningFeedbackViewController.java new file mode 100644 index 0000000000000000000000000000000000000000..f09d2e2dd0cc36f3cdc27f4a0588b961eb18445c --- /dev/null +++ b/PlayWall/src/de/tobias/playpad/viewcontroller/settings/WarningFeedbackViewController.java @@ -0,0 +1,61 @@ +package de.tobias.playpad.viewcontroller.settings; + +import de.tobias.playpad.PlayPadMain; +import de.tobias.playpad.Strings; +import de.tobias.playpad.pad.Pad; +import de.tobias.playpad.settings.Profile; +import de.tobias.playpad.settings.ProfileSettings; +import de.tobias.utils.ui.ContentViewController; +import de.tobias.utils.util.Localization; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.util.Duration; + +public class WarningFeedbackViewController extends ContentViewController { + + @FXML private Slider warningFeedbackTimeSlider; + @FXML private Label warningFeedbackTimeLabel; + + public WarningFeedbackViewController() { + super("warningFeedbackSettingsView", "de/tobias/playpad/assets/settings/", PlayPadMain.getUiResourceBundle()); + ProfileSettings profilSettings = Profile.currentProfile().getProfileSettings(); + + warningFeedbackTimeSlider.setValue(profilSettings.getWarningFeedback().getTime().toSeconds()); + setTimeLabel(); + + warningFeedbackTimeSlider.valueProperty().addListener((a, b, c) -> + { + profilSettings.getWarningFeedback().setTime(Duration.seconds(c.doubleValue())); + }); + } + + public WarningFeedbackViewController(Pad pad) { + super("warningFeedbackSettingsView", "de/tobias/playpad/assets/settings/", PlayPadMain.getUiResourceBundle()); + } + + @Override + public void init() { + warningFeedbackTimeSlider.valueProperty().addListener((a, b, c) -> + { + setTimeLabel(); + }); + } + + private void setTimeLabel() { + double displayedTime = Math.round(warningFeedbackTimeSlider.getValue() * 10) / 10.0; + warningFeedbackTimeLabel.setText(Localization.getString(Strings.Standard_Time_Seconds, displayedTime)); + } + + public void setPadWarning(Pad pad) { + if (pad.getWarning() != null) { + warningFeedbackTimeSlider.setValue(pad.getWarning().getTime().toSeconds()); + setTimeLabel(); + } + + warningFeedbackTimeSlider.valueProperty().addListener((a, b, c) -> + { + pad.getWarning().setTime(Duration.seconds(c.doubleValue())); + }); + } +} diff --git a/PlayWall/src/icon.icns b/PlayWall/src/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..0b82f6e32cec646a917652b1f7438fe6d9814b27 Binary files /dev/null and b/PlayWall/src/icon.icns differ diff --git a/PlayWall/src/icon.ico b/PlayWall/src/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..376f9b44f0795408da217e99f1ad84c7f8382ba1 Binary files /dev/null and b/PlayWall/src/icon.ico differ diff --git a/PlayWall/src/icon.png b/PlayWall/src/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e2fe4bc8d837c9cb9a166b85503af202dbf4331f Binary files /dev/null and b/PlayWall/src/icon.png differ diff --git a/PlayWall/src/icon_small.png b/PlayWall/src/icon_small.png new file mode 100644 index 0000000000000000000000000000000000000000..e8acf8263a66f86581c5b5f65f0ad11ff11bf60b Binary files /dev/null and b/PlayWall/src/icon_small.png differ diff --git a/PlayWall/test/TestPlayPad.java b/PlayWall/test/TestPlayPad.java new file mode 100644 index 0000000000000000000000000000000000000000..b8a7b9bebfc3baf679278807749018c5c5654337 --- /dev/null +++ b/PlayWall/test/TestPlayPad.java @@ -0,0 +1,37 @@ +import java.nio.file.Path; +import java.nio.file.Paths; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.DataLine.Info; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +public class TestPlayPad { + + public static void main(String[] args) throws LineUnavailableException { + Mixer mixer = AudioSystem.getMixer(AudioSystem.getMixerInfo()[0]); + + DataLine.Info info = new Info(Clip.class, null); + try { + Clip clip = (Clip) mixer.getLine(info); + + Path path = Paths.get("/Users/tobias/Downloads/TURN ALL THE LIGHTS ON.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(path.toFile()); + + clip.open(audioInputStream); + clip.start(); + + do { + Thread.sleep(50); + } while (clip.isActive()); + + clip.close(); + mixer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +}