Updates to delphinID and TDisplayFX

This commit is contained in:
Jamie Mac 2024-05-16 08:29:17 +01:00
parent 2c8d54b660
commit 83678d3c25
18 changed files with 727 additions and 546 deletions

View File

@ -411,6 +411,26 @@ public class PamArrayUtils {
return new double[] {min, max};
}
/**
* Calculate the minimum and maximum value of a 2D array.
* @param arr - the array to find the maximum value of.
* @return the minimum and maximum value in the array
*/
public static float[] minmax(float[][] arr) {
float max = Float.NEGATIVE_INFINITY;
float min = Float.POSITIVE_INFINITY;
for(int i=0; i<arr.length; i++) {
for(int j=0; j<arr[i].length; j++) {
max = Math.max(max, arr[i][j]);
min = Math.min(min, arr[i][j]);
}
}
return new float[] {min, max};
}
/**
@ -1167,6 +1187,7 @@ public class PamArrayUtils {

View File

@ -14,7 +14,8 @@ import java.util.Collection;
import java.util.List;
/**
* A series of classes to load and import data stored in text files (includes .csv files)
* Some functions to load and import data stored in text files (includes .csv files)
*
* @author Jamie Macaulay
*
*/

View File

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="150mm"
height="150mm"
viewBox="0 0 150 150"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="logo01.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.74564394"
inkscape:cx="379.53772"
inkscape:cy="512.97943"
inkscape:window-width="1242"
inkscape:window-height="1008"
inkscape:window-x="649"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs2">
<inkscape:path-effect
effect="bspline"
id="path-effect3117"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect3117-7"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
<inkscape:path-effect
effect="bspline"
id="path-effect3117-6"
is_visible="true"
lpeversion="1"
weight="33.333333"
steps="2"
helper_size="0"
apply_no_weight="true"
apply_with_weight="true"
only_selected="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="11.709678"
y="81.967743"
id="text113"><tspan
sodipodi:role="line"
id="tspan111"
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:25.4px;font-family:Calibri;-inkscape-font-specification:'Calibri, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
x="11.709678"
y="81.967743"><tspan
style="fill:#6f916f"
id="tspan167">delphin</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:Calibri;-inkscape-font-specification:'Calibri, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#0b2817"
id="tspan165">ID</tspan></tspan></text>
<path
style="fill:#6f916f;stroke-width:0.264583"
d="m 27.322579,38.322579 6.741938,2.838712"
id="path535" />
<path
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
d="m 120.67435,61.080456 c 1.55411,1.367612 3.10801,2.735039 4.219,4.735608 1.11098,2.00057 1.77914,4.634082 1.8024,7.356282 0.0232,2.7222 -0.5983,5.53298 -1.65497,7.685367 -1.05667,2.152388 -2.5484,3.646416 -4.0401,5.140414"
id="path3115"
inkscape:path-effect="#path-effect3117"
inkscape:original-d="m 120.67435,61.080456 c 1.55406,1.367671 3.10796,2.735101 4.66173,4.102301 0.66832,2.63386 1.33649,5.26737 2.00453,7.90072 -0.62143,2.81111 -1.24298,5.62189 -1.86469,8.43252 -1.49163,1.49428 -2.98336,2.98831 -4.47524,4.48213" />
<path
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
d="m 115.99401,66.369877 c 0.93292,0.812059 1.86573,1.624027 2.53264,2.81193 0.66692,1.187903 1.06802,2.751664 1.08197,4.368074 0.014,1.61641 -0.35915,3.285393 -0.99347,4.563459 -0.63431,1.278066 -1.52976,2.165182 -2.42524,3.052317"
id="path3115-4"
inkscape:path-effect="#path-effect3117-6"
inkscape:original-d="m 115.99401,66.369877 c 0.93289,0.81209 1.8657,1.62406 2.79841,2.43588 0.4012,1.56394 0.8023,3.1277 1.20331,4.69134 -0.37304,1.66922 -0.74616,3.3382 -1.11936,5.00712 -0.89543,0.88729 -1.79089,1.7744 -2.68646,2.66144" />
<path
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
d="m 125.65039,55.168033 c 2.46165,2.066818 4.923,4.133391 6.68278,7.156798 1.75977,3.023407 2.81814,7.003389 2.85497,11.117374 0.0368,4.113986 -0.9477,8.361845 -2.62144,11.614689 -1.67374,3.252844 -4.03659,5.51072 -6.39943,7.768583"
id="path3115-8"
inkscape:path-effect="#path-effect3117-7"
inkscape:original-d="m 125.65039,55.168033 c 2.46157,2.06691 4.92292,4.133487 7.38405,6.199707 1.05862,3.980467 2.11699,7.960447 3.17515,11.940157 -0.98434,4.24836 -1.96886,8.49622 -2.95363,12.74383 -2.36272,2.2583 -4.72558,4.51617 -7.08869,6.77375" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -137,7 +137,7 @@
*/
/** top-left, top-right, bottom-right, and bottom-left corners, in that order. */
.close-button-right{
-fx-background-color: -fx-darkbackground-trans;
-fx-background-color: -fx-darkbackground;
-fx-background-radius: 0 10 10 0;
-fx-border-color: transparent;
-fx-border-radius: 0 10 10 0;
@ -145,7 +145,7 @@
.close-button-left{
-fx-background-color: -fx-darkbackground-trans;
-fx-background-color: -fx-darkbackground;
-fx-background-radius: 10 0 0 10;
-fx-border-color: transparent;
-fx-border-radius: 10 0 0 10;
@ -153,7 +153,7 @@
.close-button-top{
-fx-background-color: -fx-darkbackground-trans;
-fx-background-color: -fx-darkbackground;
-fx-background-radius: 10 10 0 0;
-fx-border-color: transparent;
-fx-border-radius: 10 10 0 0;
@ -161,7 +161,7 @@
.close-button-bottom{
-fx-background-color: -fx-darkbackground-trans;
-fx-background-color: -fx-darkbackground;
-fx-background-radius: 0 0 10 10;
-fx-border-color: transparent;
-fx-border-radius: 0 0 10 10;

View File

@ -115,10 +115,10 @@ public class TDControlFX extends TDControl implements UserDisplayNodeFX {
PamDataBlock dataBlock=this.tdDisplayController.getUserDisplayProcess().getParentDataBlock();
if (TDDataProviderRegisterFX.getInstance().findDataProvider(dataBlock)!=null) dataBlocks.add(dataBlock);
if (dataBlock!=null) {
System.out.println("TDControldFX: parent datablock "+dataBlock.getDataName());
// System.out.println("TDControldFX: parent datablock "+dataBlock.getDataName());
}
else{
System.out.println("TDControldFX: parent datablock null");
// System.out.println("TDControldFX: parent datablock null");
return dataBlocks;
}

View File

@ -252,10 +252,11 @@ public class TDDisplayFX extends PamBorderPane {
//create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place
//it and what colour it is etc has to be set for whatever pane it is to be located in.
showButton=hidingControlPane.getShowButton();
showButton.getStyleClass().add("transparent-button-square");
showButton.setStyle("-fx-background-radius: 0 0 10 10;");
hidingControlPane.setShowButtonOpacity(1.0);
// showButton.getStyleClass().add("transparent-button-square");
showButton.setStyle("-fx-background-radius: 0 0 10 0;");
showButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-down", PamGuiManagerFX.iconSize));
showButton.setPrefWidth(60);
showButton.setPrefWidth(30);
showButton.setMaxHeight(timeAxisSize-20);
//create the time axis for the display.
@ -276,7 +277,7 @@ public class TDDisplayFX extends PamBorderPane {
StackPane mainGraphPane=new StackPane();
mainGraphPane.getChildren().add(splitPaneHolder);
mainGraphPane.getChildren().add(showButton);
StackPane.setAlignment(showButton, Pos.TOP_CENTER);
StackPane.setAlignment(showButton, Pos.TOP_LEFT);
this.setCenter(mainGraphPane);

View File

@ -18,20 +18,25 @@ import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamButton;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.PamStackPane;
import pamViewFX.fxNodes.PamTabPane;
import pamViewFX.fxNodes.hidingPane.HidingPane;
import pamViewFX.fxNodes.utilityPanes.PamToggleSwitch;
import pamViewFX.fxStyles.PamStylesManagerFX;
/**
@ -201,6 +206,7 @@ public class DetectionGroupDisplay extends PamBorderPane {
hidingPane.getShowButton().setGraphic(PamGlyphDude.createPamIcon("mdi2c-cog",
PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
hidingPane.setShowButtonOpacity(1.0); //don't want show button to gray out if mouse not over it
this.setRight(hidingPane); //bit of a hack but works.
hidingPane.showHidePane(false);
@ -219,36 +225,68 @@ public class DetectionGroupDisplay extends PamBorderPane {
detectionDisplayHolder = new PamStackPane();
PamTabPane settingsPane = new PamTabPane();
settingsPane.setTabMinHeight(60);
settingsPane.setMinHeight(60);
// settingsPane.repackTabs();
//this has to be before removing the heading button
settingsPane.setAddTabButton(false);
settingsPane.setTabMinHeight(60);
settingsPane.setMinHeight(100);
// settingsPane.getStyleClass().add(Styles.TABS_FLOATING);
settingsPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
//settingsPane.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());
Tab dataTab = new Tab("Data",detectionDisplay.getDataTypePane());
Tab settingsTab = new Tab("Settings -BLAH",detectionDisplay.getSettingsHolder());
PamGridPane gridPane = new PamGridPane();
gridPane.setHgap(5.);
gridPane.setVgap(5.);
gridPane.setPadding(new Insets(0,0,0,5));
gridPane.add(new Label("Plot type"), 0, 0);
gridPane.add(detectionDisplay.getDataTypePane(), 1, 0);
PamToggleSwitch showScrollSwitch = new PamToggleSwitch("Show scroll bar");
showScrollSwitch.selectedProperty().addListener((obsVal, oldVal, newVal)->{
//show or hide the scroll bar.
this.setEnableScrollBar(newVal);
});
showScrollSwitch.setSelected(true);
gridPane.add(showScrollSwitch, 0, 1);
GridPane.setColumnSpan(showScrollSwitch, GridPane.REMAINING);
Tab dataTab = new Tab("Plot",gridPane);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setContent(detectionDisplay.getSettingsHolder());
Tab settingsTab = new Tab("Settings", scrollPane);
//here add the option to show the scroll bar or not.
settingsPane.getTabs().add(dataTab);
settingsPane.getTabs().add(settingsTab);
hidingPane = new HidingPane(Side.RIGHT, settingsPane, detectionDisplayHolder, layoutType==DISPLAY_COMPACT, 0);
//set the hiding pane
Node icon = PamGlyphDude.createPamIcon("mdi2c-cog", PamGuiManagerFX.iconSize);
detectionDisplay.getPlotPane().setHidePane(new PamBorderPane(settingsPane), icon, Side.RIGHT);
//move the hiding pane button into the top of the tab pane - this makes best
//use of space.
hidingPane = detectionDisplay.getPlotPane().getHidePane(Side.RIGHT);
hidingPane.removeHideButton();
hidingPane.getHideButton().setMinWidth(40);
settingsPane.setTabStartRegion(hidingPane.getHideButton());
// hidingPane.getHideButton().getStyleClass().add("close-button-right-trans");
// hidingPane.getHideButton().setStyle(" -fx-background-radius: 0 0 0 0;");
hidingPane.setPadding(new Insets(0,0,0,0));
hidingPane.getHideButton().prefHeightProperty().bind(settingsPane.tabMinHeightProperty());
//set the show button to be slight larger
hidingPane.getShowButton().setPrefHeight(60.);
//now everything to pane.
detectionDisplayHolder.getChildren().add(detectionDisplay);
StackPane.setAlignment(detectionDisplay, Pos.CENTER);
//settingsPane.setPadding(new Insets(35,0,0,0));
Node icon = PamGlyphDude.createPamIcon("mdi2c-cog", PamGuiManagerFX.iconSize);
detectionDisplay.getPlotPane().setHidePane(new PamBorderPane(settingsPane), icon, Side.RIGHT);
hidingPane.getShowButton().setPrefHeight(30);
}
//set styles

View File

@ -6,7 +6,6 @@ import detectionPlotFX.plots.FFTSettingsPane;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import pamViewFX.fxNodes.PamSpinner;
import pamViewFX.fxNodes.PamVBox;
import whistlesAndMoans.ConnectedRegionDataUnit;

View File

@ -166,6 +166,8 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
sidePaneContent.setPadding(new Insets(25,5,5,5)); //give quite abit of spacing at the top so that there is room for close button
sidePaneContent.setMinWidth(0);
hidingSidePane=new HidingPane(Side.RIGHT, sidePaneContent, this, false);
hidingSidePane.setShowButtonOpacity(1.0);
hidingSidePane.showHidePane(false);
//create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place
@ -242,6 +244,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
mainTabPane.setTabEndRegion(showButtonRight);
mainTabPane.setTabStartRegion(showButtonLeft);
// mainTabPane.getStyleClass().add(Styles.TABS_FLOATING);
mainTabPane.getAddTabButton().setOnAction((value)->{
addPamTab(new TabInfo("Display " + (this.getNumTabs()+1)), null ,true);

View File

@ -103,7 +103,8 @@ public class PamTabPane extends TabPane {
public void setAddTabButton(boolean addTabButton) {
if (this.addTabButton==addTabButton) return;
this.addTabButton = addTabButton;
tabPaneSkin = new PamTabPaneSkin(this);
// tabPaneSkin = new PamTabPaneSkin(this);
tabPaneSkin.setAddTabButton(addTabButton);
}
/**

View File

@ -39,13 +39,13 @@ public class PamTabPaneSkin extends TabPaneSkin {
* Button which allows a new tab to be added.
*/
private PamButton addTabButton;
/**
* How many pixels the tab button 'floats' in the header area.
*/
public double addButtonInsets=3;
public PamTabPaneSkin(PamTabPane tabPane) {
super(tabPane);
this.pamTabPane=tabPane;
@ -66,7 +66,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
//add extra regions to header area
headerArea.getChildren().add(addTabButton);
}
/*
@ -82,7 +82,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
public void removeTabEndRegion(Region tabRegion){
headerArea.getChildren().remove(tabRegion);
}
/*
* Add the tab start region. This sits in the tab header area, either at the left if the tab pane is horizontal or top if the tab pane is vertical.
*/
@ -114,23 +114,23 @@ public class PamTabPaneSkin extends TabPaneSkin {
* Set the add button in the correct position
*/
private void layoutAddButton(){
//need to careful here. The width and height of the tab pane don'tr swap on rotation i.e. width of pane remains the axis on which tabs are added.
//Weird but guess the java people decided that would make programming easier.
double insetx=0.;
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
addTabButton.layoutXProperty().setValue(tabContentArea.getWidth()+insetx+headerArea.getPadding().getLeft()+addButtonInsets);
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight()+addButtonInsets);
addTabButton.resize(tabContentArea.getHeight()-4, tabContentArea.getHeight()-addButtonInsets*2);
}
else{
//yep, this makes no sense but works when tabs are vertical.
addTabButton.layoutXProperty().setValue(headerArea.getWidth()-tabContentArea.getWidth()-tabContentArea.getHeight()-headerArea.getPadding().getTop());
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight());
addTabButton.resize(tabContentArea.getHeight(),tabContentArea.getHeight());
}
// System.out.println("tab Content area width: " +tabContentArea.getWidth()+" tab Content area height: "+tabContentArea.getHeight()+ " addTabButton.layoutYProperty()" +addTabButton.layoutYProperty().getValue());
//need to careful here. The width and height of the tab pane don'tr swap on rotation i.e. width of pane remains the axis on which tabs are added.
//Weird but guess the java people decided that would make programming easier.
double insetx=0.;
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
addTabButton.layoutXProperty().setValue(tabContentArea.getWidth()+insetx+headerArea.getPadding().getLeft()+addButtonInsets);
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight()+addButtonInsets);
addTabButton.resize(tabContentArea.getHeight()-4, tabContentArea.getHeight()-addButtonInsets*2);
}
else{
//yep, this makes no sense but works when tabs are vertical.
addTabButton.layoutXProperty().setValue(headerArea.getWidth()-tabContentArea.getWidth()-tabContentArea.getHeight()-headerArea.getPadding().getTop());
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight());
addTabButton.resize(tabContentArea.getHeight(),tabContentArea.getHeight());
}
// System.out.println("tab Content area width: " +tabContentArea.getWidth()+" tab Content area height: "+tabContentArea.getHeight()+ " addTabButton.layoutYProperty()" +addTabButton.layoutYProperty().getValue());
}
@ -153,24 +153,24 @@ public class PamTabPaneSkin extends TabPaneSkin {
double startHeaderSize;
double endHeadersize;
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getLeft() : getRegionWidth(pamTabPane.getTabStartRegion());
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getRight(): getRegionWidth(pamTabPane.getTabEndRegion());
//set padding of tab header to make space for any added buttons
headerArea.setPadding(new Insets(
in.getTop(),
endHeadersize,
in.getBottom(),
startHeaderSize));
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getLeft() : getRegionWidth(pamTabPane.getTabStartRegion());
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getRight(): getRegionWidth(pamTabPane.getTabEndRegion());
//set padding of tab header to make space for any added buttons
headerArea.setPadding(new Insets(
in.getTop(),
endHeadersize,
in.getBottom(),
startHeaderSize));
}
else {
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getTop() : pamTabPane.getTabStartRegion().getHeight();
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getBottom(): pamTabPane.getTabEndRegion().getHeight();
//set padding of tab header to make space for any added buttons
headerArea.setPadding(new Insets(
startHeaderSize,
in.getRight(),
endHeadersize,
in.getLeft()));
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getTop() : pamTabPane.getTabStartRegion().getHeight();
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getBottom(): pamTabPane.getTabEndRegion().getHeight();
//set padding of tab header to make space for any added buttons
headerArea.setPadding(new Insets(
startHeaderSize,
in.getRight(),
endHeadersize,
in.getLeft()));
}
//layout additional header regions for start
@ -210,14 +210,14 @@ public class PamTabPaneSkin extends TabPaneSkin {
//System.out.println("Hello "+hello.getWidth()+" "+headerArea.getWidth()+ " "+tabContentArea.getWidth());
}
private double getRegionWidth(Region region){
double regionWidth=50;
if (region.getMinWidth()>0) regionWidth=region.getMinWidth();
if (region.getPrefWidth()>0) regionWidth=region.getPrefWidth();
return regionWidth;
}
private double getRegionHeight(Region region){
double regionHeight=50;
if (region.getMinHeight()>0) regionHeight=region.getMinHeight();
@ -240,7 +240,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
public double getHeaderHeight() {
return headerArea.getHeight();
}
/**
* Get the height property of the header.
* @return the height property of the header.
@ -248,6 +248,20 @@ public class PamTabPaneSkin extends TabPaneSkin {
public ReadOnlyDoubleProperty getHeaderHeightProperty(){
return headerArea.heightProperty();
}
public void setAddTabButton(boolean addTabButton2) {
if (addTabButton2){
if (!headerArea.getChildren().contains(addTabButton)) {
headerArea.getChildren().remove(addTabButton);
layoutAddButton();
}
}
else {
headerArea.getChildren().remove(addTabButton);
}
}
}

View File

@ -164,7 +164,7 @@ public class PamFlipPane extends FlipPane {
backButton.setStyle("-fx-background-radius: 0 5 5 0; -fx-border-radius: 0 5 5 0; -fx-background-color: -color-accent-6");
backButton.setOnAction((action)->{
System.out.println("FLIP BACK TO FRONT");
// System.out.println("FLIP BACK TO FRONT");
this.backButtonResponse.setValue(OK_BACK_BUTTON);
this.flipToFront();
});

View File

@ -13,12 +13,14 @@ import javafx.util.Duration;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.Animation.Status;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
/**
* Hiding pane which can be added to any node.
@ -32,6 +34,12 @@ import javafx.event.EventHandler;
*/
public class HidingPane extends StackPane {
/**
* The opacity of the button when the mouse is outside the show button
*/
private double showButtonOpacity = 0.25;
/**
* Which side the pane is hiding on.
*/
@ -52,7 +60,7 @@ public class HidingPane extends StackPane {
* width when shown and when aligned top.button it is the height shown.
*/
private double expandedSize=300;
/**
* Show/Hide animation time in milliseconds.
*/
@ -72,7 +80,7 @@ public class HidingPane extends StackPane {
* Button which sits in the hiding pane. Pressed to hide pane.
*/
private PamButton hideButton;
/**
* The button which shows the pane. This button isn't actually on the pane.
*/
@ -93,22 +101,22 @@ public class HidingPane extends StackPane {
* The translate property, depends on side and whether the hiding panel is overlaid or moves it's parent node.
*/
private DoubleProperty paneTanslateProperty;
/**
* The binding property for the show button. Only used when the panel is overlayed on another panel.
*/
private DoubleBinding buttonTranslateProperty;
/**
* Indicates whether the panel is showing or not;
*/
private BooleanProperty showing=new SimpleBooleanProperty(false);
/**
* If true then the pane only shows once the hide pane animation has finished
*/
private boolean visibleImmediatly=true;
/**
* The default size of the icons
*/
@ -119,7 +127,7 @@ public class HidingPane extends StackPane {
*
*/
private double offset=0;
/**
* Constructor top create a new hiding pane.
* @param side - the side the hiding pane appears from.
@ -134,14 +142,14 @@ public class HidingPane extends StackPane {
this.holderPane=holderPane;
this.overlay=overlay;
this.offset=offset;
// //CSS styling
// this.getStylesheets().add(getClass().getResource("pamSettingsCSS.css").toExternalForm());
// this.getStyleClass().add("pane");
// //CSS styling
// this.getStylesheets().add(getClass().getResource("pamSettingsCSS.css").toExternalForm());
// this.getStyleClass().add("pane");
//set the size the panel will expand to
setDefaultExpandedSize(hidePane);
//set the translate property and side index.
setTranlsateProperty();
@ -150,36 +158,36 @@ public class HidingPane extends StackPane {
styleHideButton(hideButton);
hideButton.setOnAction(new HideButtonPressed());
hideButton.setVisible(false);
// hideButton.setStyle("close-button-right");
// hideButton.setStyle("close-button-right");
//create a show button. The show button is not displayed on the hiding panel but caqn be used in other panels
showButton=createShowButton(true);
//if overlay true bind the show button to the side pane.
if (overlay) showButton.translateXProperty().bind(buttonTranslateProperty);
//set up the animation for panel showing/hiding
setAnimation();
holderPane.setMinHeight(5); //needed for hiding panes to appear outside holder pane.
// this.setMinHeight(500);
// holderPane.heightProperty().addListener((oldVall, newVal, obsVsal)->{
// if (this.getHeight()<500){
// this.setLayoutY(0);
// this.setMinHeight(500);
// holderPane.setStyle("-fx-background: red;");
// }
// System.out.println("HidingPane: LayoutY: "+this.getLayoutY() + " height "+this.getHeight());
// });
// PamBorderPane mainPane=new PamBorderPane();
// mainPane.setCenter(hidePane);
// this.setMinHeight(500);
// holderPane.heightProperty().addListener((oldVall, newVal, obsVsal)->{
// if (this.getHeight()<500){
// this.setLayoutY(0);
// this.setMinHeight(500);
// holderPane.setStyle("-fx-background: red;");
// }
// System.out.println("HidingPane: LayoutY: "+this.getLayoutY() + " height "+this.getHeight());
// });
// PamBorderPane mainPane=new PamBorderPane();
// mainPane.setCenter(hidePane);
this.getChildren().add(hidePane);
setHideButtonPos(side);
}
@ -193,36 +201,36 @@ public class HidingPane extends StackPane {
public HidingPane(final Side side, Region hidePane, Pane holderPane, boolean overlay) {
this(side, hidePane, holderPane, overlay, 0);
}
public void setShowButton(PamButton showButton) {
this.showButton = showButton;
}
public boolean isHorizontal(){
if (side==Side.TOP || side==Side.BOTTOM) return true;
return false;
}
public void resetHideAnimation(){
//set the size the panel will expand to
setDefaultExpandedSize(hidePane);
//set the translate property and side index.
setTranlsateProperty();
//set up the animation for panel showing/hiding
setAnimation();
}
/**
* Style the button to have an image of arrow.
* @param button-button to style
*/
public void styleHideButton(PamButton button){
styleHideButton(button, side);
styleHideButton(button, side);
}
/**
* Style the button to have an image of arrow.
* @param button-button to style
@ -232,34 +240,34 @@ public class HidingPane extends StackPane {
switch (side){
case RIGHT:
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelShow2.png"))));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-right", PamGuiManagerFX.iconSize));
button.getStyleClass().add("close-button-right");
break;
case LEFT:
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelHide2.png"))));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", PamGuiManagerFX.iconSize));
button.getStyleClass().add("close-button-left");
break;
case TOP:
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelUp2.png"))));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_UP, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_UP, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-up", PamGuiManagerFX.iconSize));
button.setPrefWidth(60); //horizontal buttons are slightly wider
button.getStyleClass().add("close-button-top");
break;
case BOTTOM:
//utton.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelDown2.png"))));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_DOWN, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_DOWN, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-down", PamGuiManagerFX.iconSize));
button.setPrefWidth(60); //horizontal buttons are slightly wider
button.getStyleClass().add("close-button-bottom");
break;
}
}
/**
* Set the default expanded size for the hiding panel. If the pane has a preferred size then uses this but if not then uses
* the field expandedSize to set expanded Size;
@ -267,11 +275,11 @@ public class HidingPane extends StackPane {
*/
private void setDefaultExpandedSize(Region hidePane){
boolean isHorizontal=isHorizontal();
//check if the panel has a preferred width or height depending on side position. If so set the expanded size to that;
if (!isHorizontal && hidePane.getPrefWidth()>0) expandedSize=hidePane.getPrefWidth();
else if (isHorizontal && hidePane.getPrefHeight()>0) expandedSize=hidePane.getPrefHeight();
//now set the correct preferred width for the panel
if (!isHorizontal){
hidePane.setPrefWidth(expandedSize);
@ -285,7 +293,7 @@ public class HidingPane extends StackPane {
this.setMinWidth(0);
this.setMinHeight(0);
}
/**
* If the preferred size is set for the hiding pane then the expanded size, the animation, the show
* button binding property and position of the pane must be reset.
@ -313,9 +321,9 @@ public class HidingPane extends StackPane {
//set the correct translation for the pane
if (showing.get()) paneTanslateProperty.set(overlay ? 0 : expandedSize+offset);
else paneTanslateProperty.set(overlay ? (expandedSize+offset)*sideIndex: 0);
}
/**
* Create a blank button which contains all the functionality to open or close the hiding panel, including the ability
@ -328,75 +336,95 @@ public class HidingPane extends StackPane {
private PamButton createShowButton(final boolean show){
final PamButton pamButton=new PamButton();
pamButton.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragX =mouseEvent.getSceneX();
dragY =mouseEvent.getSceneY();
}
@Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragX =mouseEvent.getSceneX();
dragY =mouseEvent.getSceneY();
}
});
pamButton.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
if (distance==0) return;
distance=sideIndex*distance;
// System.out.println("Mouse released: HidePanel distance: "+distance);
if (!overlay) distance=Math.abs(distance);
//need to see where the drag has ended-if greater than 50% then open but if less then close.
if (!isHorizontal()){
if (distance<expandedSize/2) showHidePane(overlay? true : false);
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
}
else{
if (distance<expandedSize/2) showHidePane(overlay? true : false);
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
}
//reset the distance
distance=0;
}
@Override public void handle(MouseEvent mouseEvent) {
if (distance==0) return;
distance=sideIndex*distance;
// System.out.println("Mouse released: HidePanel distance: "+distance);
if (!overlay) distance=Math.abs(distance);
//need to see where the drag has ended-if greater than 50% then open but if less then close.
if (!isHorizontal()){
if (distance<expandedSize/2) showHidePane(overlay? true : false);
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
}
else{
if (distance<expandedSize/2) showHidePane(overlay? true : false);
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
}
//reset the distance
distance=0;
}
});
pamButton.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
if (visibleImmediatly) hidePane.setVisible(true);
else hidePane.setVisible(false);
// hideButton.setVisible(true);
/**
* Work out the distance the panel is to be dragged;
*/
if (!isHorizontal()){
@Override public void handle(MouseEvent mouseEvent) {
if (visibleImmediatly) hidePane.setVisible(true);
else hidePane.setVisible(false);
// hideButton.setVisible(true);
/**
* Work out the distance the panel is to be dragged;
*/
if (!isHorizontal()){
if (!show) distance=(mouseEvent.getSceneX()-dragX);
else distance=(mouseEvent.getSceneX()-dragX)+sideIndex*expandedSize;
if (!overlay) distance=expandedSize-sideIndex*distance;
}
else{
}
else{
if (!show) distance=(mouseEvent.getSceneY()-dragY);
else distance=(mouseEvent.getSceneY()-dragY)-sideIndex*expandedSize;
if (!overlay) distance=expandedSize+sideIndex*distance;
}
// if (show && Math.abs(distance)>expandedSize) return;
translatePanel(distance);
}
});
pamButton.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
}
});
pamButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
//System.out.println("Mouse clicked");
showHidePane(show);
}
});
pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
//System.out.println("Button event");
showHidePane(show);
}
}
// if (show && Math.abs(distance)>expandedSize) return;
translatePanel(distance);
}
});
pamButton.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
// System.out.println("HidingPane.showButton - mouse entered");
pamButton.setOpacity(1.0);
pamButton.setPadding(new Insets(2.,2.,2.,2.));
}
});
pamButton.setOnMouseExited(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
// System.out.println("HidingPane.showButton - mouse exited");
if (show) pamButton.setOpacity(showButtonOpacity);
pamButton.setPadding(new Insets(0.,0.,0.,0.));
}
});
// pamButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
// @Override public void handle(MouseEvent mouseEvent) {
// System.out.println("HidingPane.showButton - mouse clicked");
// showHidePane(show);
// }
// });
pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
System.out.println("HidingPane.showButton - action event clicked");
showHidePane(show);
}
});
if (show) pamButton.setOpacity(showButtonOpacity);
return pamButton;
}
@ -425,21 +453,21 @@ public class HidingPane extends StackPane {
break;
}
}
/**
* Remove the hide button from the hiding pane. For example, used if the pane is non user controllable.
*/
public void removeHideButton(){
this.getChildren().remove(hideButton);
}
/**
* The hiding panel will have a different side Index and translateProperty depending on what the side and overlay value combination is.
* This function sets the correct values for sideIndex and translateProperty which are used in opening/closing animations and dragging the panel to an open or c
* closed position.
*/
private void setTranlsateProperty(){
/**
* Figure out the correct index and property. The sideIndex is used to tell the animation what direction to
* move the animation in. The property tells the panel either to translate in the x or y direction or
@ -481,7 +509,7 @@ public class HidingPane extends StackPane {
break;
}
}
/**
* Create a time line to show or hide a pane.
* @param paneTanslateProperty -the translate property e.g. whether to change the preferred height/width, max height/width etc.
@ -494,18 +522,18 @@ public class HidingPane extends StackPane {
// Animation for scroll SHOW.
timeLine.setCycleCount(1); //defines the number of cycles for this animation
final KeyValue kvDwn = new KeyValue(paneTanslateProperty, newSize);
// final KeyValue kvDwn = new KeyValue(translateProperty, expandedSize);
// final KeyValue kvDwn = new KeyValue(translateProperty, expandedSize);
final KeyFrame kfDwn = new KeyFrame(Duration.millis(duration), kvDwn);
timeLine.getKeyFrames().add(kfDwn);
return timeLine;
}
/**
* Set up the animation that moves the hiding panel to show and to hide. translate property and sideIndex must be set
* before calling this function.
*/
private void setAnimation(){
//Initially hiding the pane
paneTanslateProperty.set((expandedSize)*sideIndex); //+for right
@ -514,23 +542,23 @@ public class HidingPane extends StackPane {
timeLineShow = createAnimation(paneTanslateProperty, overlay ? 0-offset : expandedSize +offset , duration);
// Animation for scroll HIDE
timeLineHide = createAnimation(paneTanslateProperty, overlay ? (expandedSize +offset)*sideIndex: 0-offset , duration);
timeLineShow.setOnFinished(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
showFinished();
}
});
@Override
public void handle(ActionEvent arg0) {
showFinished();
}
});
timeLineHide.setOnFinished(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
hideFinished();
}
});
@Override
public void handle(ActionEvent arg0) {
hideFinished();
}
});
}
/**
* Called whenever the hid animation has finished.
*/
@ -540,12 +568,12 @@ public class HidingPane extends StackPane {
hidePane.setVisible(false);
hideButton.setVisible(false);
showButton.toFront();
// //TODO-delete
// System.out.println("ShowButton Size:"+showButton.getLayoutX() +" tranlateX: "+showButton.getTranslateX() +
// " tranlateY: "+showButton.getTranslateY()+" show button layoutX "+ showButton.getLayoutX()+ " "
// +showButton.getLayoutY()+ "show button width: "+showButton.getWidth());
// //TODO-delete
// System.out.println("ShowButton Size:"+showButton.getLayoutX() +" tranlateX: "+showButton.getTranslateX() +
// " tranlateY: "+showButton.getTranslateY()+" show button layoutX "+ showButton.getLayoutX()+ " "
// +showButton.getLayoutY()+ "show button width: "+showButton.getWidth());
}
/**
* Called whenever the show animation has finished.
*/
@ -554,7 +582,7 @@ public class HidingPane extends StackPane {
hidePane.setVisible(true);
hideButton.setVisible(true);
}
/**
* Move the hiding panel to show or hide a certain distance.
* @param distance. The distance in pixels to move the panel. Positive to open the panel and negative to move the panel towards closed.
@ -562,12 +590,12 @@ public class HidingPane extends StackPane {
public void translatePanel(double distance){
paneTanslateProperty.set(distance);
}
/**
* Show or hide the pane.
* @param showing-
*/
public void showHidePane(boolean show){
public synchronized void showHidePane(boolean show){
if (show) {
//the pref size may have been changed...hide pane shoulf follow this size.
showing.setValue(true);
@ -575,6 +603,11 @@ public class HidingPane extends StackPane {
//hideButton.setVisible(true);
//System.out.println("HidingPane: Open Hide Pane");
//open the panel
if (timeLineShow.getStatus()==Status.RUNNING) {
//stops the issue with the hiding pane freezing.
return;
}
timeLineShow.play();
}
else{
@ -585,7 +618,7 @@ public class HidingPane extends StackPane {
timeLineHide.play();
}
}
/**
* Show the hide pane
* @param show - tru to opne the pane. False to close the pnae
@ -604,7 +637,7 @@ public class HidingPane extends StackPane {
}
}
}
/**
* Called whenever the pin button is pressed.
* @author Jamie Macaulay
@ -624,7 +657,7 @@ public class HidingPane extends StackPane {
public PamButton getHideButton() {
return hideButton;
}
/**
* Get the button which shows the hide pane. This is generally not on the pane itself but needs to be
* added to another pane.
@ -649,7 +682,7 @@ public class HidingPane extends StackPane {
public void setDuration(long duration) {
this.duration = duration;
}
/**
* Get the pane which contains this hiding pane.
* @return the pane the hiding pane is located in.
@ -657,7 +690,7 @@ public class HidingPane extends StackPane {
public Pane getHolderPane() {
return holderPane;
}
/**
* Get the timeline which opens hiding tab pane.
* @return TimelIne which opens the hiding pane.
@ -673,7 +706,7 @@ public class HidingPane extends StackPane {
public Timeline getTimeLineHide() {
return timeLineHide;
}
/**
* Check whether the hide pane shows content at the start of the hide animation or end.
@ -682,7 +715,7 @@ public class HidingPane extends StackPane {
public boolean isVisibleImmediatly() {
return visibleImmediatly;
}
/**
* Set whether the hide pane shows content at the start of the hide animation or end.
* @param true if shows the pane at the start of the animation.
@ -690,7 +723,7 @@ public class HidingPane extends StackPane {
public void setVisibleImmediatly(boolean visibleImmediatly) {
this.visibleImmediatly = visibleImmediatly;
}
/**
* The showing property for the hiding pane.
* @return the showing property
@ -698,53 +731,71 @@ public class HidingPane extends StackPane {
public BooleanProperty showingProperty(){
return this.showing;
}
/**
* Get the opacity of the show button when the mouse is outside the button.
* @return the opacity of the show button.
*/
public double getShowButtonOpacity() {
return showButtonOpacity;
}
// hideSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
// @Override public void handle(ActionEvent actionEvent) {
// setVisible(false);
// controlButton.setText("Show");
// controlButton.getStyleClass().remove("hide-left");
// controlButton.getStyleClass().add("show-right");
// }
//});
//
//
//showSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
// @Override public void handle(ActionEvent actionEvent) {
// controlButton.setText("Collapse");
// controlButton.getStyleClass().add("hide-left");
// controlButton.getStyleClass().remove("show-right");
// }
//});
// // create an animation to hide sidebar.
// final Animation hideSidebar = new Transition() {
// { setCycleDuration(Duration.millis(50)); }
// protected void interpolate(double frac) {
// final double curWidth = expandedWidth * (1.0 - frac);
// setPrefWidth(curWidth);
// setTranslateX(curWidth);
// }
// };
//
// // create an animation to show a sidebar.
// final Animation showSidebar = new Transition() {
// { setCycleDuration(Duration.millis(duration)); }
// protected void interpolate(double frac) {
// final double curWidth = expandedWidth * frac;
// setPrefWidth(curWidth);
// setTranslateX(expandedWidth-curWidth);
// }
// };
// if (showSidebar.statusProperty().get() == Animation.Status.STOPPED && hideSidebar.statusProperty().get() == Animation.Status.STOPPED) {
// if (isVisible()) {
// hideSidebar.play();
// } else {
// setVisible(true);
// showSidebar.play();
// }
// }
/**
* Set the opacity of the show button when the mouse is outside.
* @return the opacity of the show button - set to 1.0 for no chnage when mouse outside the button.
*/
public void setShowButtonOpacity(double showButtonOpacity) {
this.showButtonOpacity = showButtonOpacity;
this.showButton.setOpacity(showButtonOpacity);
}
// hideSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
// @Override public void handle(ActionEvent actionEvent) {
// setVisible(false);
// controlButton.setText("Show");
// controlButton.getStyleClass().remove("hide-left");
// controlButton.getStyleClass().add("show-right");
// }
//});
//
//
//showSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
// @Override public void handle(ActionEvent actionEvent) {
// controlButton.setText("Collapse");
// controlButton.getStyleClass().add("hide-left");
// controlButton.getStyleClass().remove("show-right");
// }
//});
// // create an animation to hide sidebar.
// final Animation hideSidebar = new Transition() {
// { setCycleDuration(Duration.millis(50)); }
// protected void interpolate(double frac) {
// final double curWidth = expandedWidth * (1.0 - frac);
// setPrefWidth(curWidth);
// setTranslateX(curWidth);
// }
// };
//
// // create an animation to show a sidebar.
// final Animation showSidebar = new Transition() {
// { setCycleDuration(Duration.millis(duration)); }
// protected void interpolate(double frac) {
// final double curWidth = expandedWidth * frac;
// setPrefWidth(curWidth);
// setTranslateX(expandedWidth-curWidth);
// }
// };
// if (showSidebar.statusProperty().get() == Animation.Status.STOPPED && hideSidebar.statusProperty().get() == Animation.Status.STOPPED) {
// if (isVisible()) {
// hideSidebar.play();
// } else {
// setVisible(true);
// showSidebar.play();
// }
// }
}

View File

@ -213,9 +213,7 @@ public class PamHiddenSidePane extends PamStackPane {
break;
}
//make show button same height as hide button
// showButton.prefHeightProperty().bind(hidingPane.getHideButton().heightProperty());
//translate it so it sits slightly below the top of the pane.
//set the location of the show button to be in the middle of the pane
showButton.translateYProperty().bind(displayPane.heightProperty().divide(2).subtract(showButton.heightProperty().divide(2)));
hidingPane.getHideButton().translateYProperty().setValue(yPos);

View File

@ -27,177 +27,14 @@ import whistlesAndMoans.AbstractWhistleDataUnit;
*/
public class DelphinIDTest {
public static DelphinIDWorkerTest prepDelphinIDModel(String modelPath) {
//create the delphinID worker.
DelphinIDWorkerTest delphinIDWorker = new DelphinIDWorkerTest();
StandardModelParams params = new StandardModelParams();
params.modelPath = modelPath;
//prepare the model
delphinIDWorker.prepModel(params, null);
return delphinIDWorker;
}
/**
* Load whistle contours from a MAT file. ()
*
* @param filePath - the file path.
*
* @return a list of whistle contour objects from the mat file.
*/
public static ArrayList<AbstractWhistleDataUnit> getWhistleContoursMAT(String filePath){
ArrayList<AbstractWhistleDataUnit> contours = new ArrayList<AbstractWhistleDataUnit>();
// SegmenterDetectionGroup segmenterDetectionGroup = new SegmenterDetectionGroup(0, 0, 0, 0);
// Read scalar from nested struct
try {
Mat5File matFile = Mat5.readFromFile(filePath);
Struct whistlesStruct = matFile.getStruct("whistles");
double fftLen = matFile.getMatrix("fftlen").getDouble(0);
double fftHop = matFile.getMatrix("ffthop").getDouble(0);
double sampleRate = matFile.getMatrix("samplerate").getDouble(0);
for (int i=0; i< whistlesStruct.getNumElements(); i++) {
DataUnitBaseData basicData = new DataUnitBaseData();
long timeMillis = ((Matrix)whistlesStruct.get("millis", i)).getLong(0);
basicData.setTimeMilliseconds(timeMillis);
long sampleDuration = ((Matrix)whistlesStruct.get("sampleDuration", i)).getLong(0);
basicData.setSampleDuration(sampleDuration);
basicData.setMillisecondDuration(1000.*(sampleDuration/sampleRate));
int channelMap = ((Matrix)whistlesStruct.get("channelMap", i)).getInt(0);
basicData.setChannelBitmap(channelMap);
long uid = ((Matrix)whistlesStruct.get("UID", i)).getLong(0);
basicData.setUID(uid);
long startSample = ((Matrix)whistlesStruct.get("startSample", i)).getLong(0);
basicData.setStartSample(startSample);
int nSlices = ((Matrix)whistlesStruct.get("nSlices", i)).getInt(0);
double[] freq = new double[nSlices];
double[] times = new double[nSlices];
Matrix contourStruct = whistlesStruct.getMatrix("contour", i);
for (int j=0; j<nSlices; j++) {
freq[j] = contourStruct.getDouble(j)*sampleRate/fftLen;
times[j] = j * fftHop /sampleRate;
}
contours.add(new WhistleContourMAT(basicData, freq, times));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return contours;
}
/**
* Segment the detections into groups. Note that segments are overlaps so each whistle may belong to multiple segments.
* @param whistles - a list of whistles - not necessarily sorted by time.
* @param dataStartMillis - the start time of the data in millis i.e. where the first segment starts.
* @param segLen - the segment size in milliseconds.
* @param segHop - the segment hop in milliseconds.
* @return groups of data units within each segment.
*/
public static ArrayList<SegmenterDetectionGroup> segmentWhsitleData(ArrayList<AbstractWhistleDataUnit> whistles, long dataStartMillis,
double segLen, double segHop){
ArrayList<SegmenterDetectionGroup> group = new ArrayList<SegmenterDetectionGroup>();
//find the maximum whistle time
long maxTime = Long.MIN_VALUE;
long endTime = 0;
for (AbstractWhistleDataUnit whislte: whistles) {
endTime = (long) (whislte.getTimeMilliseconds()+whislte.getDurationInMilliseconds());
if (endTime>maxTime) maxTime=endTime;
}
long segStart = dataStartMillis;
long segEnd = (long) (segStart+segLen);
long whistleStart;
long whistleEnd;
SegmenterDetectionGroup whistleGroup;
while (segStart<endTime){
whistleGroup = new SegmenterDetectionGroup(segStart, 1, segEnd, segLen);
for (AbstractWhistleDataUnit whislte: whistles) {
whistleStart = whislte.getTimeMilliseconds();
whistleEnd = (long) (whislte.getTimeMilliseconds() + whislte.getDurationInMilliseconds());
if ((whistleStart>=segStart && whistleStart<segEnd) || ((whistleEnd>=segStart && whistleEnd<segEnd))){
//some part of the whistle is in the segment.
whistleGroup.addSubDetection(whislte);
}
}
group.add(whistleGroup);
// System.out.println("SegStart: " + (segStart - dataStartMillis));
segStart = (long) (segStart+segHop);
segEnd = (long) (segStart+segLen);
}
return group;
}
public static class WhistleContourMAT extends AbstractWhistleDataUnit {
private double[] freq;
private double[] times;
public WhistleContourMAT(DataUnitBaseData basicData, double[] freq, double[] times) {
super(basicData);
this.freq=freq;
this.times=times;
}
@Override
public int getSliceCount() {
return freq.length;
}
@Override
public double[] getTimesInSeconds() {
return times;
}
@Override
public double[] getFreqsHz() {
return freq;
}
}
public static class DelphinIDWorkerTest extends DelphinIDWorker {
private float[][][] lastModelInput;
public float[][][] dataUnits2ModelInput(ArrayList<? extends PamDataUnit> dataUnits, float sampleRate, int iChan){
float[][][] data = super.dataUnits2ModelInput(dataUnits, sampleRate, iChan);
this.lastModelInput = data;
@ -237,10 +74,10 @@ public class DelphinIDTest {
MatFile matFile = Mat5.newMatFile();
//get the whislte contours form a .mat file.
ArrayList<AbstractWhistleDataUnit> whistleContours = getWhistleContoursMAT(whistleContourPath);
ArrayList<AbstractWhistleDataUnit> whistleContours = DelphinIDUtils.getWhistleContoursMAT(whistleContourPath);
//segment the whistle detections
ArrayList<SegmenterDetectionGroup> segments = segmentWhsitleData(whistleContours, (long) (dataStartMillis+(9.565*1000.)),
ArrayList<SegmenterDetectionGroup> segments = DelphinIDUtils.segmentWhsitleData(whistleContours, (long) (dataStartMillis+(9.565*1000.)),
segLen, segHop);
for (int i=0; i<segments.size(); i++) {
@ -248,7 +85,7 @@ public class DelphinIDTest {
}
//prepare the model - this loads the zip file and loads the correct transforms.
DelphinIDWorkerTest model = prepDelphinIDModel(modelPath);
DelphinIDWorkerTest model = DelphinIDUtils.prepDelphinIDModel(modelPath);
model.setEnableSoftMax(false);

View File

@ -0,0 +1,3 @@
package rawDeepLearningClassifier.dlClassification.delphinID;

View File

@ -0,0 +1,330 @@
package rawDeepLearningClassifier.dlClassification.delphinID;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import PamUtils.FileList;
import PamUtils.PamArrayUtils;
import PamUtils.TxtFileUtils;
import PamguardMVC.DataUnitBaseData;
import PamguardMVC.PamDataUnit;
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
import rawDeepLearningClassifier.dlClassification.delphinID.DelphinIDTest.DelphinIDWorkerTest;
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
import us.hebi.matlab.mat.format.Mat5;
import us.hebi.matlab.mat.format.Mat5File;
import us.hebi.matlab.mat.types.Matrix;
import us.hebi.matlab.mat.types.Struct;
import whistlesAndMoans.AbstractWhistleDataUnit;
/**
* A bunch of utility functions that a re useful for testing and running
* DelphinID models
*/
public class DelphinIDUtils {
public static DelphinIDWorkerTest prepDelphinIDModel(String modelPath) {
//create the delphinID worker.
DelphinIDWorkerTest delphinIDWorker = new DelphinIDWorkerTest();
StandardModelParams params = new StandardModelParams();
params.modelPath = modelPath;
//prepare the model
delphinIDWorker.prepModel(params, null);
return delphinIDWorker;
}
/**
* Load whistle contours from a MAT file. ()
*
* @param filePath - the file path.
*
* @return a list of whistle contour objects from the mat file.
*/
public static ArrayList<AbstractWhistleDataUnit> getWhistleContoursMAT(String filePath){
ArrayList<AbstractWhistleDataUnit> contours = new ArrayList<AbstractWhistleDataUnit>();
// SegmenterDetectionGroup segmenterDetectionGroup = new SegmenterDetectionGroup(0, 0, 0, 0);
// Read scalar from nested struct
try {
Mat5File matFile = Mat5.readFromFile(filePath);
Struct whistlesStruct = matFile.getStruct("whistles");
double fftLen = matFile.getMatrix("fftlen").getDouble(0);
double fftHop = matFile.getMatrix("ffthop").getDouble(0);
double sampleRate = matFile.getMatrix("samplerate").getDouble(0);
return getWhistleContoursMAT(whistlesStruct, fftLen, fftHop, sampleRate);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return contours;
}
/**
* Load whistle contours from a MATLAB struct
* @param whistlesStruct - a struct containing a list of whistle contours
* @param fftLen- the fft length in samples
* @param fftHop - the fft hop in samples.
* @param sampleRate - the sample rate in samples per second.
* @return a list of whistle contour objects from the struct.
*/
public static ArrayList<AbstractWhistleDataUnit> getWhistleContoursMAT(Struct whistlesStruct, double fftLen, double fftHop, double sampleRate){
ArrayList<AbstractWhistleDataUnit> contours = new ArrayList<AbstractWhistleDataUnit>();
for (int i=0; i< whistlesStruct.getNumElements(); i++) {
DataUnitBaseData basicData = new DataUnitBaseData();
long timeMillis = ((Matrix)whistlesStruct.get("millis", i)).getLong(0);
basicData.setTimeMilliseconds(timeMillis);
long sampleDuration = ((Matrix)whistlesStruct.get("sampleDuration", i)).getLong(0);
basicData.setSampleDuration(sampleDuration);
basicData.setMillisecondDuration(1000.*(sampleDuration/sampleRate));
int channelMap = ((Matrix)whistlesStruct.get("channelMap", i)).getInt(0);
basicData.setChannelBitmap(channelMap);
long uid = ((Matrix)whistlesStruct.get("UID", i)).getLong(0);
basicData.setUID(uid);
long startSample = ((Matrix)whistlesStruct.get("startSample", i)).getLong(0);
basicData.setStartSample(startSample);
int nSlices = ((Matrix)whistlesStruct.get("nSlices", i)).getInt(0);
double[] freq = new double[nSlices];
double[] times = new double[nSlices];
Matrix contourStruct = whistlesStruct.getMatrix("contour", i);
for (int j=0; j<nSlices; j++) {
freq[j] = contourStruct.getDouble(j)*sampleRate/fftLen;
times[j] = j * fftHop /sampleRate;
}
contours.add(new WhistleContourMAT(basicData, freq, times));
}
return contours;
}
/**
* Segment the detections into groups. Note that segments are overlaps so each whistle may belong to multiple segments.
* @param whistles - a list of whistles - not necessarily sorted by time.
* @param dataStartMillis - the start time of the data in millis i.e. where the first segment starts.
* @param segLen - the segment size in milliseconds.
* @param segHop - the segment hop in milliseconds.
* @return groups of data units within each segment.
*/
public static ArrayList<SegmenterDetectionGroup> segmentWhsitleData(ArrayList<AbstractWhistleDataUnit> whistles, long dataStartMillis,
double segLen, double segHop){
ArrayList<SegmenterDetectionGroup> group = new ArrayList<SegmenterDetectionGroup>();
//find the maximum whistle time
long maxTime = Long.MIN_VALUE;
long endTime = 0;
for (AbstractWhistleDataUnit whislte: whistles) {
endTime = (long) (whislte.getTimeMilliseconds()+whislte.getDurationInMilliseconds());
if (endTime>maxTime) maxTime=endTime;
}
long segStart = dataStartMillis;
long segEnd = (long) (segStart+segLen);
long whistleStart;
long whistleEnd;
SegmenterDetectionGroup whistleGroup;
while (segStart<endTime){
whistleGroup = new SegmenterDetectionGroup(segStart, 1, segEnd, segLen);
for (AbstractWhistleDataUnit whislte: whistles) {
whistleStart = whislte.getTimeMilliseconds();
whistleEnd = (long) (whislte.getTimeMilliseconds() + whislte.getDurationInMilliseconds());
if ((whistleStart>=segStart && whistleStart<segEnd) || ((whistleEnd>=segStart && whistleEnd<segEnd))){
//some part of the whistle is in the segment.
whistleGroup.addSubDetection(whislte);
}
}
group.add(whistleGroup);
// System.out.println("SegStart: " + (segStart - dataStartMillis));
segStart = (long) (segStart+segHop);
segEnd = (long) (segStart+segLen);
}
return group;
}
public static class WhistleContourMAT extends AbstractWhistleDataUnit {
private double[] freq;
private double[] times;
public WhistleContourMAT(DataUnitBaseData basicData, double[] freq, double[] times) {
super(basicData);
this.freq=freq;
this.times=times;
}
@Override
public int getSliceCount() {
return freq.length;
}
@Override
public double[] getTimesInSeconds() {
return times;
}
@Override
public double[] getFreqsHz() {
return freq;
}
}
private static void generateImages(Struct whistlesStruct, String outName, DelphinIDWorker worker, double fftLen, double fftHop, double sampleRate) {
double segLen = 4000.;
double segHop = 1000.0;
// ArrayList<ArrayList<Double>> contourData = TxtFileUtils.importCSVData(csvFile);
ArrayList<AbstractWhistleDataUnit> whistles = getWhistleContoursMAT(whistlesStruct, fftLen, fftHop, sampleRate);
//segment the whistle detections
ArrayList<SegmenterDetectionGroup> segments = DelphinIDUtils.segmentWhsitleData(whistles, whistles.get(0).getTimeMilliseconds(), segLen, segHop);
float[][][] images = worker.dataUnits2ModelInput(segments, (float) sampleRate, 0);
float[][] image;
BufferedImage bfImage;
for (int k=0; k<images.length; k++) {
image = images[k];
bfImage = new BufferedImage(image.length, image[0].length, BufferedImage.TYPE_INT_RGB);
// System.out.println("Max of image: " + PamArrayUtils.minmax(image)[1]);
for(int i = 0; i < image.length; i++) {
for(int j = 0; j < image[0].length; j++) {
Color myRGB = new Color(image[i][j], image[i][j], image[i][j]);
int rgb = myRGB.getRGB();
bfImage.setRGB(i, j, rgb);
}
}
//now save the image
String outputPath = outName + "_" + k + ".png";
File outputfile = new File(outputPath);
try {
ImageIO.write(bfImage, "png", outputfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//the whsitle contours as csv files.
String whistlefolder = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD";
//the image folder to save to.
String imageFolder = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD_Images";
//the path to the model
String modelPath = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_model_2/whistle_4s_415.zip";
//prepare the model - this loads the zip file and loads the correct transforms.
DelphinIDWorkerTest model;
model = DelphinIDUtils.prepDelphinIDModel(modelPath);
model.setEnableSoftMax(false);
FileList filelist = new FileList();
File folder = new File(whistlefolder);
File[] listOfFiles = folder.listFiles();
if(listOfFiles != null) {
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isDirectory()) {
//get a list of csv files
// ArrayList<File> csvFiles = filelist.getFileList(listOfFiles[i].getAbsolutePath(), ".mat" , true);
System.out.println("Directory " + listOfFiles[i].getName());
File outFolder = new File(imageFolder + File.separator + listOfFiles[i].getName());
outFolder.mkdir();//make the out folder directory
try {
File file = new File(listOfFiles[i].getPath() + File.separator + "whistles.mat");
Mat5File matFile = Mat5.readFromFile(file);
Struct whistlesStruct = matFile.getStruct("whistles");
double fftLen = matFile.getMatrix("fftlen").getDouble(0);
double fftHop = matFile.getMatrix("ffthop").getDouble(0);
double sampleRate = matFile.getMatrix("samplerate").getDouble(0);
List<String> fieldNames = whistlesStruct.getFieldNames();
Struct whistecontours;
for (String name: fieldNames) {
System.out.println("Generating images for recording " + name + " from " + listOfFiles[i].getName());
if (!name.equals("fftlen") && !name.equals("ffthop") && !name.equals("samplerate")) {
whistecontours = whistlesStruct.get(name);
generateImages( whistecontours, (outFolder + File.separator + name) , model, fftLen, fftHop, sampleRate);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}

View File

@ -95,9 +95,7 @@ public class DelphinIDWorker extends ArchiveModelWorker {
return whistle2ImageParmas;
}
}
//something has gone wrong if we get here.
return null;
}