Improve showcases
BIN
.screenshots/titlepage/blueprints.png
Normal file
After Width: | Height: | Size: 195 KiB |
BIN
.screenshots/titlepage/fm.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
.screenshots/titlepage/mp.png
Normal file
After Width: | Height: | Size: 195 KiB |
BIN
.screenshots/titlepage/page.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
.screenshots/titlepage/themes.png
Normal file
After Width: | Height: | Size: 35 KiB |
@ -18,7 +18,11 @@ See the <a href="https://mkpaz.github.io/atlantafx/">docs</a> for more info.
|
|||||||
</b></p>
|
</b></p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/demo.gif" alt="Logo"/><br/>
|
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/titlepage/blueprints.png" alt="blueprints"/><br/>
|
||||||
|
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/titlepage/fm.png" alt="apps"/><br/>
|
||||||
|
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/titlepage/mp.png" alt="apps"/><br/>
|
||||||
|
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/titlepage/page.png" alt="page"/><br/>
|
||||||
|
<img src="https://raw.githubusercontent.com/mkpaz/atlantafx/master/.screenshots/titlepage/themes.png" alt="themes"/><br/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
* Flat interface inspired by the variety of Web component frameworks.
|
* Flat interface inspired by the variety of Web component frameworks.
|
||||||
|
2
pom.xml
@ -59,7 +59,7 @@
|
|||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<openjfx.version>19</openjfx.version>
|
<openjfx.version>20</openjfx.version>
|
||||||
<sass.version>1.54.4</sass.version>
|
<sass.version>1.54.4</sass.version>
|
||||||
|
|
||||||
<app.name>AtlantaFX</app.name>
|
<app.name>AtlantaFX</app.name>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.layout;
|
package atlantafx.sampler.layout;
|
||||||
|
|
||||||
import atlantafx.sampler.util.Containers;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
@ -21,7 +21,7 @@ public final class ApplicationWindow extends AnchorPane {
|
|||||||
new Overlay(),
|
new Overlay(),
|
||||||
new MainLayer()
|
new MainLayer()
|
||||||
);
|
);
|
||||||
Containers.setAnchors(body, Insets.EMPTY);
|
NodeUtils.setAnchors(body, Insets.EMPTY);
|
||||||
|
|
||||||
getChildren().setAll(body);
|
getChildren().setAll(body);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import atlantafx.sampler.Resources;
|
|||||||
import atlantafx.sampler.event.DefaultEventBus;
|
import atlantafx.sampler.event.DefaultEventBus;
|
||||||
import atlantafx.sampler.event.PageEvent;
|
import atlantafx.sampler.event.PageEvent;
|
||||||
import atlantafx.sampler.theme.HighlightJSTheme;
|
import atlantafx.sampler.theme.HighlightJSTheme;
|
||||||
import atlantafx.sampler.util.Containers;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
@ -48,7 +48,7 @@ final class CodeViewer extends AnchorPane {
|
|||||||
private void lazyLoadWebView() {
|
private void lazyLoadWebView() {
|
||||||
if (webView == null) {
|
if (webView == null) {
|
||||||
webView = new WebView();
|
webView = new WebView();
|
||||||
Containers.setAnchors(webView, Insets.EMPTY);
|
NodeUtils.setAnchors(webView, Insets.EMPTY);
|
||||||
getChildren().add(0, webView);
|
getChildren().add(0, webView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,8 @@ class MainLayer extends BorderPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
WritableImage img = page.getSnapshotTarget().snapshot(new SnapshotParameters(), null);
|
SnapshotParameters sp = new SnapshotParameters();
|
||||||
|
WritableImage img = page.getSnapshotTarget().snapshot(sp, null);
|
||||||
ImageIO.write(SwingFXUtils.fromFXImage(img, null), "png", file);
|
ImageIO.write(SwingFXUtils.fromFXImage(img, null), "png", file);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
|
@ -48,7 +48,7 @@ import atlantafx.sampler.page.components.TreeTableViewPage;
|
|||||||
import atlantafx.sampler.page.components.TreeViewPage;
|
import atlantafx.sampler.page.components.TreeViewPage;
|
||||||
import atlantafx.sampler.page.general.BBCodePage;
|
import atlantafx.sampler.page.general.BBCodePage;
|
||||||
import atlantafx.sampler.page.general.IconsPage;
|
import atlantafx.sampler.page.general.IconsPage;
|
||||||
import atlantafx.sampler.page.showcase.OverviewPage;
|
import atlantafx.sampler.page.showcase.BlueprintsPage;
|
||||||
import atlantafx.sampler.page.general.ThemePage;
|
import atlantafx.sampler.page.general.ThemePage;
|
||||||
import atlantafx.sampler.page.general.TypographyPage;
|
import atlantafx.sampler.page.general.TypographyPage;
|
||||||
import atlantafx.sampler.page.showcase.filemanager.FileManagerPage;
|
import atlantafx.sampler.page.showcase.filemanager.FileManagerPage;
|
||||||
@ -214,7 +214,7 @@ public class MainModel {
|
|||||||
|
|
||||||
var showcases = NavTree.Item.group("Showcase", new FontIcon(Material2OutlinedMZ.VISIBILITY));
|
var showcases = NavTree.Item.group("Showcase", new FontIcon(Material2OutlinedMZ.VISIBILITY));
|
||||||
showcases.getChildren().setAll(
|
showcases.getChildren().setAll(
|
||||||
NAV_TREE.get(OverviewPage.class),
|
NAV_TREE.get(BlueprintsPage.class),
|
||||||
NAV_TREE.get(FileManagerPage.class),
|
NAV_TREE.get(FileManagerPage.class),
|
||||||
NAV_TREE.get(MusicPlayerPage.class)
|
NAV_TREE.get(MusicPlayerPage.class)
|
||||||
);
|
);
|
||||||
@ -310,7 +310,7 @@ public class MainModel {
|
|||||||
map.put(TreeViewPage.class, NavTree.Item.page(TreeViewPage.NAME, TreeViewPage.class));
|
map.put(TreeViewPage.class, NavTree.Item.page(TreeViewPage.NAME, TreeViewPage.class));
|
||||||
|
|
||||||
// showcases
|
// showcases
|
||||||
map.put(OverviewPage.class, NavTree.Item.page(OverviewPage.NAME, OverviewPage.class));
|
map.put(BlueprintsPage.class, NavTree.Item.page(BlueprintsPage.NAME, BlueprintsPage.class));
|
||||||
map.put(FileManagerPage.class, NavTree.Item.page(FileManagerPage.NAME, FileManagerPage.class));
|
map.put(FileManagerPage.class, NavTree.Item.page(FileManagerPage.NAME, FileManagerPage.class));
|
||||||
map.put(MusicPlayerPage.class, NavTree.Item.page(MusicPlayerPage.NAME, MusicPlayerPage.class));
|
map.put(MusicPlayerPage.class, NavTree.Item.page(MusicPlayerPage.NAME, MusicPlayerPage.class));
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package atlantafx.sampler.layout;
|
package atlantafx.sampler.layout;
|
||||||
|
|
||||||
import atlantafx.sampler.util.Animations;
|
import atlantafx.sampler.util.Animations;
|
||||||
import atlantafx.sampler.util.Containers;
|
|
||||||
import atlantafx.sampler.util.NodeUtils;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -51,7 +50,7 @@ public final class Overlay extends StackPane {
|
|||||||
centerContentWrapper.setAlignment(Pos.CENTER);
|
centerContentWrapper.setAlignment(Pos.CENTER);
|
||||||
|
|
||||||
scrollPane = new ScrollPane();
|
scrollPane = new ScrollPane();
|
||||||
Containers.setScrollConstraints(scrollPane,
|
NodeUtils.setScrollConstraints(scrollPane,
|
||||||
ScrollPane.ScrollBarPolicy.AS_NEEDED, true,
|
ScrollPane.ScrollBarPolicy.AS_NEEDED, true,
|
||||||
ScrollPane.ScrollBarPolicy.NEVER, true
|
ScrollPane.ScrollBarPolicy.NEVER, true
|
||||||
);
|
);
|
||||||
@ -108,11 +107,11 @@ public final class Overlay extends StackPane {
|
|||||||
switch (pos) {
|
switch (pos) {
|
||||||
case LEFT -> {
|
case LEFT -> {
|
||||||
edgeContentWrapper.getChildren().setAll(content);
|
edgeContentWrapper.getChildren().setAll(content);
|
||||||
Containers.setAnchors(content, new Insets(0, -1, 0, 0));
|
NodeUtils.setAnchors(content, new Insets(0, -1, 0, 0));
|
||||||
}
|
}
|
||||||
case RIGHT -> {
|
case RIGHT -> {
|
||||||
edgeContentWrapper.getChildren().setAll(content);
|
edgeContentWrapper.getChildren().setAll(content);
|
||||||
Containers.setAnchors(content, new Insets(0, 0, 0, -1));
|
NodeUtils.setAnchors(content, new Insets(0, 0, 0, -1));
|
||||||
}
|
}
|
||||||
case CENTER -> {
|
case CENTER -> {
|
||||||
centerContentWrapper.getChildren().setAll(content);
|
centerContentWrapper.getChildren().setAll(content);
|
||||||
|
@ -8,7 +8,6 @@ import static atlantafx.base.theme.Styles.FLAT;
|
|||||||
import static atlantafx.base.theme.Styles.TITLE_4;
|
import static atlantafx.base.theme.Styles.TITLE_4;
|
||||||
|
|
||||||
import atlantafx.base.controls.Spacer;
|
import atlantafx.base.controls.Spacer;
|
||||||
import atlantafx.sampler.util.Containers;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
@ -70,8 +69,10 @@ public abstract class OverlayDialog<T extends Region> extends VBox {
|
|||||||
VBox.setVgrow(footerBox, Priority.NEVER);
|
VBox.setVgrow(footerBox, Priority.NEVER);
|
||||||
|
|
||||||
// IMPORTANT: this guarantees client will use correct width and height
|
// IMPORTANT: this guarantees client will use correct width and height
|
||||||
Containers.usePrefWidth(this);
|
setMinWidth(USE_PREF_SIZE);
|
||||||
Containers.usePrefHeight(this);
|
setMaxWidth(USE_PREF_SIZE);
|
||||||
|
setMinHeight(USE_PREF_SIZE);
|
||||||
|
setMaxHeight(USE_PREF_SIZE);
|
||||||
|
|
||||||
// if you're updating this line, update setContent() method as well
|
// if you're updating this line, update setContent() method as well
|
||||||
getChildren().setAll(headerBox, footerBox);
|
getChildren().setAll(headerBox, footerBox);
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.page;
|
package atlantafx.sampler.page;
|
||||||
|
|
||||||
import static atlantafx.sampler.util.Containers.setScrollConstraints;
|
|
||||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
||||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
||||||
|
|
||||||
import atlantafx.base.util.BBCodeParser;
|
import atlantafx.base.util.BBCodeParser;
|
||||||
import atlantafx.sampler.layout.Overlay;
|
import atlantafx.sampler.layout.Overlay;
|
||||||
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@ -39,7 +39,7 @@ public abstract class AbstractPage extends StackPane implements Page {
|
|||||||
userContent.setMaxWidth(Math.min(Page.MAX_WIDTH, 800));
|
userContent.setMaxWidth(Math.min(Page.MAX_WIDTH, 800));
|
||||||
|
|
||||||
var scrollPane = new ScrollPane(userContentArea);
|
var scrollPane = new ScrollPane(userContentArea);
|
||||||
setScrollConstraints(scrollPane, AS_NEEDED, true, NEVER, true);
|
NodeUtils.setScrollConstraints(scrollPane, AS_NEEDED, true, NEVER, true);
|
||||||
scrollPane.setMaxHeight(20_000);
|
scrollPane.setMaxHeight(20_000);
|
||||||
|
|
||||||
getChildren().setAll(scrollPane);
|
getChildren().setAll(scrollPane);
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.page;
|
package atlantafx.sampler.page;
|
||||||
|
|
||||||
import static atlantafx.sampler.util.Containers.setScrollConstraints;
|
|
||||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
||||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.NEVER;
|
||||||
|
|
||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import atlantafx.sampler.layout.Overlay;
|
import atlantafx.sampler.layout.Overlay;
|
||||||
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -58,7 +58,7 @@ public abstract class OutlinePage extends StackPane implements Page {
|
|||||||
userContent.setMaxWidth(Page.MAX_WIDTH - OUTLINE_WIDTH - 100);
|
userContent.setMaxWidth(Page.MAX_WIDTH - OUTLINE_WIDTH - 100);
|
||||||
|
|
||||||
scrollPane.setContent(userContentArea);
|
scrollPane.setContent(userContentArea);
|
||||||
setScrollConstraints(scrollPane, AS_NEEDED, true, NEVER, true);
|
NodeUtils.setScrollConstraints(scrollPane, AS_NEEDED, true, NEVER, true);
|
||||||
scrollPane.setMaxHeight(20_000);
|
scrollPane.setMaxHeight(20_000);
|
||||||
|
|
||||||
// scroll spy
|
// scroll spy
|
||||||
|
@ -10,7 +10,6 @@ import static atlantafx.sampler.util.ContrastLevel.getContrastRatioOpacityAware;
|
|||||||
import static atlantafx.sampler.util.JColorUtils.flattenColor;
|
import static atlantafx.sampler.util.JColorUtils.flattenColor;
|
||||||
|
|
||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import atlantafx.sampler.util.Containers;
|
|
||||||
import atlantafx.sampler.util.ContrastLevel;
|
import atlantafx.sampler.util.ContrastLevel;
|
||||||
import atlantafx.sampler.util.NodeUtils;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -51,17 +50,17 @@ final class ColorPaletteBlock extends VBox {
|
|||||||
contrastRatioText = new Text();
|
contrastRatioText = new Text();
|
||||||
contrastRatioText.setStyle("-fx-fill:" + fgColorName + ";");
|
contrastRatioText.setStyle("-fx-fill:" + fgColorName + ";");
|
||||||
contrastRatioText.getStyleClass().addAll("contrast-ratio-text", TITLE_3);
|
contrastRatioText.getStyleClass().addAll("contrast-ratio-text", TITLE_3);
|
||||||
Containers.setAnchors(contrastRatioText, new Insets(5, -1, -1, 5));
|
NodeUtils.setAnchors(contrastRatioText, new Insets(5, -1, -1, 5));
|
||||||
|
|
||||||
contrastLevelLabel.setGraphic(contrastLevelIcon);
|
contrastLevelLabel.setGraphic(contrastLevelIcon);
|
||||||
contrastLevelLabel.getStyleClass().add("contrast-level-label");
|
contrastLevelLabel.getStyleClass().add("contrast-level-label");
|
||||||
contrastLevelLabel.setVisible(false);
|
contrastLevelLabel.setVisible(false);
|
||||||
Containers.setAnchors(contrastLevelLabel, new Insets(-1, 3, 3, -1));
|
NodeUtils.setAnchors(contrastLevelLabel, new Insets(-1, 3, 3, -1));
|
||||||
|
|
||||||
editIcon.setIconSize(24);
|
editIcon.setIconSize(24);
|
||||||
editIcon.getStyleClass().add("edit-icon");
|
editIcon.getStyleClass().add("edit-icon");
|
||||||
NodeUtils.toggleVisibility(editIcon, false);
|
NodeUtils.toggleVisibility(editIcon, false);
|
||||||
Containers.setAnchors(editIcon, new Insets(3, 3, -1, -1));
|
NodeUtils.setAnchors(editIcon, new Insets(3, 3, -1, -1));
|
||||||
|
|
||||||
colorRectangle = new AnchorPane();
|
colorRectangle = new AnchorPane();
|
||||||
colorRectangle.setStyle(
|
colorRectangle.setStyle(
|
||||||
|
@ -14,7 +14,7 @@ import atlantafx.base.controls.Spacer;
|
|||||||
import atlantafx.sampler.theme.SamplerTheme;
|
import atlantafx.sampler.theme.SamplerTheme;
|
||||||
import atlantafx.sampler.theme.ThemeManager;
|
import atlantafx.sampler.theme.ThemeManager;
|
||||||
import atlantafx.sampler.theme.ThemeRepository;
|
import atlantafx.sampler.theme.ThemeRepository;
|
||||||
import atlantafx.sampler.util.Containers;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -63,7 +63,7 @@ final class ThemeRepoManager extends VBox {
|
|||||||
REPO.getAll().forEach(theme -> themeList.getChildren().add(themeCell(theme)));
|
REPO.getAll().forEach(theme -> themeList.getChildren().add(themeCell(theme)));
|
||||||
|
|
||||||
var scrollPane = new ScrollPane(themeList);
|
var scrollPane = new ScrollPane(themeList);
|
||||||
Containers.setScrollConstraints(scrollPane, AS_NEEDED, true, AS_NEEDED, true);
|
NodeUtils.setScrollConstraints(scrollPane, AS_NEEDED, true, AS_NEEDED, true);
|
||||||
scrollPane.setMaxHeight(4000);
|
scrollPane.setMaxHeight(4000);
|
||||||
VBox.setVgrow(scrollPane, ALWAYS);
|
VBox.setVgrow(scrollPane, ALWAYS);
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.page.showcase;
|
package atlantafx.sampler.page.showcase;
|
||||||
|
|
||||||
import static atlantafx.sampler.util.Containers.setScrollConstraints;
|
|
||||||
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
import static javafx.scene.control.ScrollPane.ScrollBarPolicy.AS_NEEDED;
|
||||||
|
|
||||||
import atlantafx.sampler.Resources;
|
import atlantafx.sampler.Resources;
|
||||||
import atlantafx.sampler.page.Page;
|
import atlantafx.sampler.page.Page;
|
||||||
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
@ -19,17 +19,17 @@ import javafx.scene.layout.Priority;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public final class OverviewPage extends ScrollPane implements Page {
|
public final class BlueprintsPage extends ScrollPane implements Page {
|
||||||
|
|
||||||
public static final String NAME = "Overview";
|
public static final String NAME = "Blueprints";
|
||||||
private VBox wrapper;
|
private final VBox wrapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverviewPage() {
|
public BlueprintsPage() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -37,21 +37,21 @@ public final class OverviewPage extends ScrollPane implements Page {
|
|||||||
wrapper.setAlignment(Pos.TOP_CENTER);
|
wrapper.setAlignment(Pos.TOP_CENTER);
|
||||||
|
|
||||||
var loader = new FXMLLoader(
|
var loader = new FXMLLoader(
|
||||||
Resources.getResource("assets/fxml/overview/index.fxml").toURL()
|
Resources.getResource("assets/fxml/blueprints/index.fxml").toURL()
|
||||||
);
|
);
|
||||||
Parent fxmlContent = loader.load();
|
Parent fxmlContent = loader.load();
|
||||||
((Pane) fxmlContent).setMaxWidth(Page.MAX_WIDTH);
|
((Pane) fxmlContent).setMaxWidth(Page.MAX_WIDTH);
|
||||||
VBox.setVgrow(fxmlContent, Priority.ALWAYS);
|
VBox.setVgrow(fxmlContent, Priority.ALWAYS);
|
||||||
wrapper.getChildren().setAll(fxmlContent);
|
wrapper.getChildren().setAll(fxmlContent);
|
||||||
|
|
||||||
setScrollConstraints(this, AS_NEEDED, true, AS_NEEDED, true);
|
NodeUtils.setScrollConstraints(this, AS_NEEDED, true, AS_NEEDED, true);
|
||||||
setMaxHeight(20_000);
|
setMaxHeight(20_000);
|
||||||
setContent(wrapper);
|
setContent(wrapper);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Unable to load FXML file", e);
|
throw new RuntimeException("Unable to load FXML file", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
setId("overview");
|
setId("blueprints");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -11,6 +11,7 @@ import javafx.css.PseudoClass;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
@ -30,6 +31,7 @@ public abstract class ShowcasePage extends StackPane implements Page {
|
|||||||
protected VBox showcaseWindow = new VBox();
|
protected VBox showcaseWindow = new VBox();
|
||||||
protected Label windowTitle = new Label();
|
protected Label windowTitle = new Label();
|
||||||
protected VBox showCaseContent = new VBox();
|
protected VBox showCaseContent = new VBox();
|
||||||
|
protected FontIcon aboutBtn = new FontIcon(Feather.HELP_CIRCLE);
|
||||||
protected int windowWidth = DEFAULT_WIDTH;
|
protected int windowWidth = DEFAULT_WIDTH;
|
||||||
protected int windowHeight = DEFAULT_HEIGHT;
|
protected int windowHeight = DEFAULT_HEIGHT;
|
||||||
protected BooleanProperty maximized = new SimpleBooleanProperty();
|
protected BooleanProperty maximized = new SimpleBooleanProperty();
|
||||||
@ -43,11 +45,15 @@ public abstract class ShowcasePage extends StackPane implements Page {
|
|||||||
protected void createShowcaseLayout() {
|
protected void createShowcaseLayout() {
|
||||||
windowTitle.getStyleClass().addAll("title");
|
windowTitle.getStyleClass().addAll("title");
|
||||||
|
|
||||||
|
aboutBtn.getStyleClass().addAll(Styles.SMALL, Styles.FLAT);
|
||||||
|
|
||||||
var maximizeBtn = new FontIcon(Feather.MAXIMIZE_2);
|
var maximizeBtn = new FontIcon(Feather.MAXIMIZE_2);
|
||||||
maximizeBtn.getStyleClass().addAll(Styles.SMALL, Styles.FLAT);
|
maximizeBtn.getStyleClass().addAll(Styles.SMALL, Styles.FLAT);
|
||||||
maximizeBtn.setOnMouseClicked(e -> maximized.set(!maximized.get()));
|
maximizeBtn.setOnMouseClicked(e -> maximized.set(!maximized.get()));
|
||||||
|
|
||||||
var windowHeader = new HBox(windowTitle, new Spacer(), maximizeBtn);
|
var windowHeader = new HBox(
|
||||||
|
20, windowTitle, new Spacer(), aboutBtn, maximizeBtn
|
||||||
|
);
|
||||||
windowHeader.getStyleClass().add("header");
|
windowHeader.getStyleClass().add("header");
|
||||||
|
|
||||||
showcaseWindow.getStyleClass().add("window");
|
showcaseWindow.getStyleClass().add("window");
|
||||||
@ -75,6 +81,18 @@ public abstract class ShowcasePage extends StackPane implements Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setAboutInfo(String text) {
|
||||||
|
var tooltip = new Tooltip(text);
|
||||||
|
tooltip.setWrapText(true);
|
||||||
|
tooltip.setMaxWidth(300);
|
||||||
|
aboutBtn.setOnMouseEntered(e -> {
|
||||||
|
var localBounds = aboutBtn.getBoundsInLocal();
|
||||||
|
var screenBounds = aboutBtn.localToScreen(localBounds);
|
||||||
|
tooltip.show(getScene().getWindow(), screenBounds.getCenterX(), screenBounds.getMaxY());
|
||||||
|
});
|
||||||
|
aboutBtn.setOnMouseExited(e -> tooltip.hide());
|
||||||
|
}
|
||||||
|
|
||||||
protected void setShowCaseContent(Node node) {
|
protected void setShowCaseContent(Node node) {
|
||||||
setShowCaseContent(node, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
setShowCaseContent(node, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
|
||||||
|
|
||||||
package atlantafx.sampler.page.showcase.filemanager;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import org.kordamp.ikonli.Ikon;
|
|
||||||
|
|
||||||
record Bookmark(String title, Path path, Ikon icon) {
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package atlantafx.sampler.page.showcase.filemanager;
|
|
||||||
|
|
||||||
import static atlantafx.sampler.page.showcase.filemanager.Model.USER_HOME;
|
|
||||||
|
|
||||||
import atlantafx.base.theme.Tweaks;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import javafx.scene.control.Alert;
|
|
||||||
import javafx.scene.control.ListCell;
|
|
||||||
import javafx.scene.control.ListView;
|
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import org.kordamp.ikonli.feather.Feather;
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
|
||||||
|
|
||||||
final class BookmarkList extends ListView<Bookmark> {
|
|
||||||
|
|
||||||
public BookmarkList(Model model) {
|
|
||||||
getStyleClass().addAll("bookmark-list", Tweaks.EDGE_TO_EDGE);
|
|
||||||
|
|
||||||
// this is Linux specific and only for EN locale
|
|
||||||
getItems().setAll(
|
|
||||||
new Bookmark("Home", USER_HOME, Feather.HOME),
|
|
||||||
new Bookmark("Documents", USER_HOME.resolve("Documents"), Feather.FILE),
|
|
||||||
new Bookmark("Downloads", USER_HOME.resolve("Downloads"), Feather.DOWNLOAD),
|
|
||||||
new Bookmark("Music", USER_HOME.resolve("Music"), Feather.MUSIC),
|
|
||||||
new Bookmark("Pictures", USER_HOME.resolve("Pictures"), Feather.IMAGE),
|
|
||||||
new Bookmark("Videos", USER_HOME.resolve("Videos"), Feather.VIDEO)
|
|
||||||
);
|
|
||||||
|
|
||||||
setCellFactory(param -> {
|
|
||||||
var cell = new BookmarkCell();
|
|
||||||
cell.setOnMousePressed((MouseEvent event) -> {
|
|
||||||
if (cell.isEmpty() || cell.getItem() == null) {
|
|
||||||
event.consume();
|
|
||||||
} else {
|
|
||||||
Path path = cell.getItem().path();
|
|
||||||
|
|
||||||
if (!Files.exists(path)) {
|
|
||||||
var alert = new Alert(Alert.AlertType.WARNING);
|
|
||||||
alert.setTitle("Error Dialog");
|
|
||||||
alert.setHeaderText("Sorry, this is just demo.");
|
|
||||||
alert.setContentText("There's no such directory as \"" + path + "\"");
|
|
||||||
alert.initOwner(getScene().getWindow());
|
|
||||||
alert.showAndWait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
model.navigate(path, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return cell;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private static class BookmarkCell extends ListCell<Bookmark> {
|
|
||||||
|
|
||||||
public BookmarkCell() {
|
|
||||||
setGraphicTextGap(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateItem(Bookmark bookmark, boolean empty) {
|
|
||||||
super.updateItem(bookmark, empty);
|
|
||||||
|
|
||||||
if (empty) {
|
|
||||||
setGraphic(null);
|
|
||||||
setText(null);
|
|
||||||
} else {
|
|
||||||
setGraphic(new FontIcon(bookmark.icon()));
|
|
||||||
setText(bookmark.title());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,88 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
package atlantafx.sampler.page.showcase.filemanager;
|
||||||
|
|
||||||
|
import static atlantafx.sampler.page.showcase.filemanager.Utils.isFileHidden;
|
||||||
|
|
||||||
|
import atlantafx.base.theme.Tweaks;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import javafx.scene.control.TreeCell;
|
||||||
|
import javafx.scene.control.TreeItem;
|
||||||
|
import javafx.scene.control.TreeView;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
|
||||||
|
final class DirectoryTree extends TreeView<File> {
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public DirectoryTree(Model model, File rootPath) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
getStyleClass().add(Tweaks.ALT_ICON);
|
||||||
|
|
||||||
|
var root = new TreeItem<>(rootPath);
|
||||||
|
root.setExpanded(true);
|
||||||
|
setRoot(root);
|
||||||
|
|
||||||
|
// scan file tree two levels deep for starters
|
||||||
|
scan(root, 2);
|
||||||
|
|
||||||
|
setCellFactory(c -> new TreeCell<>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(File item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
|
setText(null);
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
setText(item.getName());
|
||||||
|
|
||||||
|
var image = new ImageView(FileIconRepository.FOLDER);
|
||||||
|
image.setFitWidth(20);
|
||||||
|
image.setFitHeight(20);
|
||||||
|
setGraphic(image);
|
||||||
|
|
||||||
|
pseudoClassStateChanged(Model.HIDDEN, isFileHidden(item.toPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// scan deeper as the user navigates down the tree
|
||||||
|
root.addEventHandler(TreeItem.branchExpandedEvent(), event -> {
|
||||||
|
TreeItem parent = event.getTreeItem();
|
||||||
|
parent.getChildren().forEach(child -> {
|
||||||
|
var item = (TreeItem<File>) child;
|
||||||
|
if (item.getChildren().isEmpty()) {
|
||||||
|
scan(item, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
getSelectionModel().selectedItemProperty().addListener((obs, old, item) -> {
|
||||||
|
if (item != null && item.getValue() != null) {
|
||||||
|
model.navigate(item.getValue().toPath(), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void scan(TreeItem<File> parent, int depth) {
|
||||||
|
File[] files = parent.getValue().listFiles();
|
||||||
|
depth--;
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
for (File f : files) {
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
var item = new TreeItem<>(f);
|
||||||
|
parent.getChildren().add(item);
|
||||||
|
|
||||||
|
if (depth > 0) {
|
||||||
|
scan(item, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.getChildren().sort(
|
||||||
|
Comparator.comparing(TreeItem::getValue)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,11 +11,13 @@ import javafx.scene.image.Image;
|
|||||||
|
|
||||||
final class FileIconRepository {
|
final class FileIconRepository {
|
||||||
|
|
||||||
private static final String IMAGE_DIRECTORY = "images/papirus/";
|
public static final String IMAGE_DIRECTORY = "images/papirus/";
|
||||||
public static final Image UNKNOWN_FILE =
|
public static final Image UNKNOWN_FILE = new Image(
|
||||||
new Image(Resources.getResourceAsStream(IMAGE_DIRECTORY + "mimetypes/text-plain.png"));
|
Resources.getResourceAsStream(IMAGE_DIRECTORY + "mimetypes/text-plain.png")
|
||||||
public static final Image FOLDER =
|
);
|
||||||
new Image(Resources.getResourceAsStream(IMAGE_DIRECTORY + "places/folder-blue.png"));
|
public static final Image FOLDER = new Image(
|
||||||
|
Resources.getResourceAsStream(IMAGE_DIRECTORY + "places/folder-paleorange.png")
|
||||||
|
);
|
||||||
|
|
||||||
private final Map<String, Image> cache = new HashMap<>();
|
private final Map<String, Image> cache = new HashMap<>();
|
||||||
private final Set<String> unknownMimeTypes = new HashSet<>();
|
private final Set<String> unknownMimeTypes = new HashSet<>();
|
||||||
|
@ -21,8 +21,9 @@ import javafx.scene.control.TableView;
|
|||||||
|
|
||||||
final class FileList {
|
final class FileList {
|
||||||
|
|
||||||
static final Comparator<Path> FILE_TYPE_COMPARATOR =
|
static final Comparator<Path> FILE_TYPE_COMPARATOR = Comparator.comparing(
|
||||||
Comparator.comparing(path -> !Files.isDirectory(path));
|
path -> !Files.isDirectory(path)
|
||||||
|
);
|
||||||
static final Predicate<Path> PREDICATE_ANY = path -> true;
|
static final Predicate<Path> PREDICATE_ANY = path -> true;
|
||||||
static final Predicate<Path> PREDICATE_NOT_HIDDEN = path -> !isFileHidden(path);
|
static final Predicate<Path> PREDICATE_NOT_HIDDEN = path -> !isFileHidden(path);
|
||||||
|
|
||||||
|
@ -2,19 +2,16 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.page.showcase.filemanager;
|
package atlantafx.sampler.page.showcase.filemanager;
|
||||||
|
|
||||||
import static atlantafx.base.theme.Styles.BUTTON_ICON;
|
|
||||||
import static atlantafx.base.theme.Styles.FLAT;
|
|
||||||
import static atlantafx.sampler.page.showcase.filemanager.FileList.PREDICATE_ANY;
|
import static atlantafx.sampler.page.showcase.filemanager.FileList.PREDICATE_ANY;
|
||||||
import static atlantafx.sampler.page.showcase.filemanager.FileList.PREDICATE_NOT_HIDDEN;
|
import static atlantafx.sampler.page.showcase.filemanager.FileList.PREDICATE_NOT_HIDDEN;
|
||||||
import static atlantafx.sampler.page.showcase.filemanager.Utils.openFile;
|
import static atlantafx.sampler.page.showcase.filemanager.Utils.openFile;
|
||||||
import static atlantafx.sampler.util.Controls.iconButton;
|
|
||||||
|
|
||||||
import atlantafx.base.controls.Breadcrumbs;
|
import atlantafx.base.controls.Breadcrumbs;
|
||||||
import atlantafx.base.controls.Breadcrumbs.BreadCrumbItem;
|
import atlantafx.base.controls.Breadcrumbs.BreadCrumbItem;
|
||||||
import atlantafx.base.controls.Spacer;
|
import atlantafx.base.controls.Spacer;
|
||||||
import atlantafx.base.theme.Tweaks;
|
import atlantafx.base.theme.Styles;
|
||||||
import atlantafx.sampler.page.showcase.ShowcasePage;
|
import atlantafx.sampler.page.showcase.ShowcasePage;
|
||||||
import atlantafx.sampler.util.Containers;
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -25,19 +22,22 @@ import javafx.geometry.Insets;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ButtonBase;
|
import javafx.scene.control.ButtonBase;
|
||||||
import javafx.scene.control.CheckMenuItem;
|
import javafx.scene.control.ContentDisplay;
|
||||||
|
import javafx.scene.control.Hyperlink;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.MenuButton;
|
|
||||||
import javafx.scene.control.MenuItem;
|
|
||||||
import javafx.scene.control.SplitPane;
|
import javafx.scene.control.SplitPane;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
import javafx.scene.control.ToolBar;
|
import javafx.scene.control.ToolBar;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
import org.kordamp.ikonli.feather.Feather;
|
import org.kordamp.ikonli.feather.Feather;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
import org.kordamp.ikonli.material2.Material2AL;
|
import org.kordamp.ikonli.material2.Material2AL;
|
||||||
import org.kordamp.ikonli.material2.Material2MZ;
|
import org.kordamp.ikonli.material2.Material2OutlinedAL;
|
||||||
|
|
||||||
public class FileManagerPage extends ShowcasePage {
|
public class FileManagerPage extends ShowcasePage {
|
||||||
|
|
||||||
@ -59,31 +59,40 @@ public class FileManagerPage extends ShowcasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createView() {
|
private void createView() {
|
||||||
var backBtn = iconButton(Feather.ARROW_LEFT, false);
|
var backBtn = new Button("", new FontIcon(Feather.ARROW_LEFT));
|
||||||
|
backBtn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
|
backBtn.getStyleClass().add(Styles.BUTTON_ICON);
|
||||||
backBtn.setOnAction(e -> model.back());
|
backBtn.setOnAction(e -> model.back());
|
||||||
backBtn.disableProperty().bind(model.getHistory().canGoBackProperty().not());
|
backBtn.disableProperty().bind(model.getHistory().canGoBackProperty().not());
|
||||||
|
backBtn.setTooltip(new Tooltip("Back"));
|
||||||
|
|
||||||
var forthBtn = iconButton(Feather.ARROW_RIGHT, false);
|
var forthBtn = new Button("", new FontIcon(Feather.ARROW_RIGHT));
|
||||||
|
forthBtn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
|
forthBtn.getStyleClass().add(Styles.BUTTON_ICON);
|
||||||
forthBtn.setOnAction(e -> model.forth());
|
forthBtn.setOnAction(e -> model.forth());
|
||||||
forthBtn.disableProperty().bind(model.getHistory().canGoForthProperty().not());
|
forthBtn.disableProperty().bind(model.getHistory().canGoForthProperty().not());
|
||||||
|
forthBtn.setTooltip(new Tooltip("Forward"));
|
||||||
|
|
||||||
Breadcrumbs<Path> breadcrumbs = breadCrumbs();
|
Breadcrumbs<Path> breadcrumbs = createBreadcrumbs();
|
||||||
|
breadcrumbs.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
HBox.setHgrow(breadcrumbs, Priority.ALWAYS);
|
||||||
breadcrumbs.setOnCrumbAction(e -> model.navigate(e.getSelectedCrumb().getValue(), true));
|
breadcrumbs.setOnCrumbAction(e -> model.navigate(e.getSelectedCrumb().getValue(), true));
|
||||||
|
|
||||||
var createMenuBtn = new MenuButton();
|
var createBtn = new Button(null, new FontIcon(Feather.FOLDER));
|
||||||
createMenuBtn.setText("New");
|
createBtn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
createMenuBtn.getItems().setAll(
|
createBtn.getStyleClass().add(Styles.BUTTON_ICON);
|
||||||
new MenuItem("New Folder"),
|
|
||||||
new MenuItem("New Document")
|
|
||||||
);
|
|
||||||
|
|
||||||
var toggleHiddenCheck = new CheckMenuItem("Show Hidden Files");
|
var treeTgl = new ToggleButton("", new FontIcon(Material2OutlinedAL.ACCOUNT_TREE));
|
||||||
toggleHiddenCheck.setSelected(false);
|
treeTgl.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
|
treeTgl.getStyleClass().add(Styles.BUTTON_ICON);
|
||||||
|
treeTgl.setSelected(true);
|
||||||
|
treeTgl.setTooltip(new Tooltip("Show tree"));
|
||||||
|
|
||||||
var menuBtn = new MenuButton();
|
var hiddenTgl = new ToggleButton("", new FontIcon(Material2OutlinedAL.FILTER_LIST));
|
||||||
menuBtn.setGraphic(new FontIcon(Material2MZ.MENU));
|
hiddenTgl.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
menuBtn.getItems().setAll(toggleHiddenCheck);
|
hiddenTgl.getStyleClass().add(Styles.BUTTON_ICON);
|
||||||
menuBtn.getStyleClass().addAll(BUTTON_ICON, Tweaks.NO_ARROW);
|
hiddenTgl.setSelected(true);
|
||||||
|
hiddenTgl.setTooltip(new Tooltip("Show hidden files"));
|
||||||
|
|
||||||
var topBar = new ToolBar();
|
var topBar = new ToolBar();
|
||||||
topBar.getItems().setAll(
|
topBar.getItems().setAll(
|
||||||
@ -91,18 +100,19 @@ public class FileManagerPage extends ShowcasePage {
|
|||||||
forthBtn,
|
forthBtn,
|
||||||
new Spacer(10),
|
new Spacer(10),
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
new Spacer(),
|
new Spacer(10),
|
||||||
createMenuBtn,
|
treeTgl,
|
||||||
menuBtn
|
hiddenTgl
|
||||||
);
|
);
|
||||||
|
|
||||||
// ~
|
// ~
|
||||||
|
var dirTree = new DirectoryTree(model, Model.USER_HOME.toFile());
|
||||||
|
dirTree.setMinWidth(100);
|
||||||
|
|
||||||
BookmarkList bookmarksList = new BookmarkList(model);
|
var dirView = new TableDirectoryView();
|
||||||
|
dirView.setMinWidth(300);
|
||||||
DirectoryView directoryView = new TableDirectoryView();
|
dirView.setDirectory(model.currentPathProperty().get());
|
||||||
directoryView.setDirectory(model.currentPathProperty().get());
|
dirView.setOnAction(path -> {
|
||||||
directoryView.setOnAction(path -> {
|
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
model.navigate(path, true);
|
model.navigate(path, true);
|
||||||
} else {
|
} else {
|
||||||
@ -111,25 +121,32 @@ public class FileManagerPage extends ShowcasePage {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ~
|
// ~
|
||||||
|
var splitPane = new SplitPane(dirTree, dirView.getView());
|
||||||
var splitPane = new SplitPane(bookmarksList, directoryView.getView());
|
|
||||||
splitPane.widthProperty().addListener(
|
splitPane.widthProperty().addListener(
|
||||||
// set sidebar width in pixels depending on split pane width
|
// set sidebar width in pixels depending on split pane width
|
||||||
(obs, old, val) -> splitPane.setDividerPosition(0, 200 / splitPane.getWidth())
|
(obs, old, val) -> splitPane.setDividerPosition(0, 300 / splitPane.getWidth())
|
||||||
);
|
);
|
||||||
|
|
||||||
var root = new BorderPane();
|
var root = new BorderPane();
|
||||||
root.getStyleClass().add("file-manager-showcase");
|
root.setId("file-manager-showcase");
|
||||||
root.getStylesheets().add(STYLESHEET_URL);
|
root.getStylesheets().add(STYLESHEET_URL);
|
||||||
root.setTop(new VBox(topBar));
|
root.setTop(new VBox(topBar));
|
||||||
root.setCenter(splitPane);
|
root.setCenter(splitPane);
|
||||||
//root.setBottom(creditsBox);
|
|
||||||
|
|
||||||
toggleHiddenCheck.selectedProperty().addListener((obs, old, val) -> directoryView.getFileList()
|
hiddenTgl.selectedProperty().addListener((obs, old, val) -> dirView.getFileList()
|
||||||
.predicateProperty()
|
.predicateProperty()
|
||||||
.set(val ? PREDICATE_ANY : PREDICATE_NOT_HIDDEN)
|
.set(!val ? PREDICATE_ANY : PREDICATE_NOT_HIDDEN)
|
||||||
);
|
);
|
||||||
directoryView.getFileList().predicateProperty().set(PREDICATE_NOT_HIDDEN);
|
dirView.getFileList().predicateProperty().set(PREDICATE_NOT_HIDDEN);
|
||||||
|
|
||||||
|
treeTgl.selectedProperty().addListener((obs, old, val) -> {
|
||||||
|
if (val) {
|
||||||
|
splitPane.getItems().add(0, dirTree);
|
||||||
|
splitPane.setDividerPosition(0, 300 / splitPane.getWidth());
|
||||||
|
} else {
|
||||||
|
splitPane.getItems().remove(dirTree);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
model.currentPathProperty().addListener((obs, old, val) -> {
|
model.currentPathProperty().addListener((obs, old, val) -> {
|
||||||
if (!Files.isReadable(val)) {
|
if (!Files.isReadable(val)) {
|
||||||
@ -141,25 +158,30 @@ public class FileManagerPage extends ShowcasePage {
|
|||||||
breadcrumbs.setSelectedCrumb(
|
breadcrumbs.setSelectedCrumb(
|
||||||
Breadcrumbs.buildTreeModel(getParentPath(val, 4).toArray(Path[]::new))
|
Breadcrumbs.buildTreeModel(getParentPath(val, 4).toArray(Path[]::new))
|
||||||
);
|
);
|
||||||
directoryView.setDirectory(val);
|
dirView.setDirectory(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
setWindowTitle("File Manager", new FontIcon(Material2AL.FOLDER));
|
setWindowTitle("File Manager", new FontIcon(Material2AL.FOLDER));
|
||||||
setShowCaseContent(root);
|
setAboutInfo("""
|
||||||
|
This is a simple file manager. You can navigate through \
|
||||||
|
the file system and open files using the default system application."""
|
||||||
|
);
|
||||||
|
setShowCaseContent(root, MAX_WIDTH, 600);
|
||||||
|
|
||||||
Containers.setAnchors(root, Insets.EMPTY);
|
NodeUtils.setAnchors(root, Insets.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Breadcrumbs<Path> breadCrumbs() {
|
private Breadcrumbs<Path> createBreadcrumbs() {
|
||||||
Callback<BreadCrumbItem<Path>, ButtonBase> crumbFactory = crumb -> {
|
Callback<BreadCrumbItem<Path>, ButtonBase> crumbFactory = crumb -> {
|
||||||
var btn = new Button(crumb.getValue().getFileName().toString());
|
var hyperlink = new Hyperlink(crumb.getValue().getFileName().toString());
|
||||||
btn.getStyleClass().add(FLAT);
|
hyperlink.setFocusTraversable(false);
|
||||||
btn.setFocusTraversable(false);
|
return hyperlink;
|
||||||
return btn;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Callback<BreadCrumbItem<Path>, ? extends Node> dividerFactory = item ->
|
Callback<BreadCrumbItem<Path>, ? extends Node> dividerFactory = item ->
|
||||||
item != null && !item.isLast() ? new Label("", new FontIcon(Material2AL.CHEVRON_RIGHT)) : null;
|
item != null && !item.isLast()
|
||||||
|
? new Label("", new FontIcon(Material2AL.CHEVRON_RIGHT))
|
||||||
|
: null;
|
||||||
|
|
||||||
var breadcrumbs = new Breadcrumbs<Path>();
|
var breadcrumbs = new Breadcrumbs<Path>();
|
||||||
breadcrumbs.setAutoNavigationEnabled(false);
|
breadcrumbs.setAutoNavigationEnabled(false);
|
||||||
|
@ -7,9 +7,12 @@ import java.nio.file.Paths;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
import javafx.css.PseudoClass;
|
||||||
|
|
||||||
final class Model {
|
final class Model {
|
||||||
|
|
||||||
|
public static final PseudoClass HIDDEN = PseudoClass.getPseudoClass("hidden");
|
||||||
|
public static final PseudoClass FOLDER = PseudoClass.getPseudoClass("folder");
|
||||||
public static final Path USER_HOME = Paths.get(System.getProperty("user.home"));
|
public static final Path USER_HOME = Paths.get(System.getProperty("user.home"));
|
||||||
|
|
||||||
private final ReadOnlyObjectWrapper<Path> currentPath = new ReadOnlyObjectWrapper<>();
|
private final ReadOnlyObjectWrapper<Path> currentPath = new ReadOnlyObjectWrapper<>();
|
||||||
|
@ -17,9 +17,11 @@ final class NavigationHistory {
|
|||||||
private final IntegerProperty cursor = new SimpleIntegerProperty(0);
|
private final IntegerProperty cursor = new SimpleIntegerProperty(0);
|
||||||
private final List<Path> history = new ArrayList<>();
|
private final List<Path> history = new ArrayList<>();
|
||||||
private final BooleanBinding canGoBack = Bindings.createBooleanBinding(
|
private final BooleanBinding canGoBack = Bindings.createBooleanBinding(
|
||||||
() -> cursor.get() > 0 && history.size() > 1, cursor);
|
() -> cursor.get() > 0 && history.size() > 1, cursor
|
||||||
|
);
|
||||||
private final BooleanBinding canGoForth = Bindings.createBooleanBinding(
|
private final BooleanBinding canGoForth = Bindings.createBooleanBinding(
|
||||||
() -> cursor.get() < history.size() - 1, cursor);
|
() -> cursor.get() < history.size() - 1, cursor
|
||||||
|
);
|
||||||
|
|
||||||
public void append(Path path) {
|
public void append(Path path) {
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
|
@ -5,6 +5,8 @@ package atlantafx.sampler.page.showcase.filemanager;
|
|||||||
import static javafx.scene.input.KeyCombination.CONTROL_DOWN;
|
import static javafx.scene.input.KeyCombination.CONTROL_DOWN;
|
||||||
|
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.CustomMenuItem;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.SeparatorMenuItem;
|
import javafx.scene.control.SeparatorMenuItem;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
@ -18,31 +20,50 @@ final class RightClickMenu extends ContextMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createMenu() {
|
private void createMenu() {
|
||||||
var open = new MenuItem("Open");
|
var openItem = new MenuItem("Open");
|
||||||
|
|
||||||
var cut = new MenuItem("Cut");
|
var cutItem = new MenuItem("Cut");
|
||||||
cut.setAccelerator(new KeyCodeCombination(KeyCode.X, CONTROL_DOWN));
|
cutItem.setAccelerator(new KeyCodeCombination(KeyCode.X, CONTROL_DOWN));
|
||||||
|
|
||||||
var copy = new MenuItem("Copy");
|
var copyItem = new MenuItem("Copy");
|
||||||
copy.setAccelerator(new KeyCodeCombination(KeyCode.C, CONTROL_DOWN));
|
copyItem.setAccelerator(new KeyCodeCombination(KeyCode.C, CONTROL_DOWN));
|
||||||
|
|
||||||
var rename = new MenuItem("Rename");
|
var renameItem = new MenuItem("Rename");
|
||||||
rename.setAccelerator(new KeyCodeCombination(KeyCode.F2));
|
renameItem.setAccelerator(new KeyCodeCombination(KeyCode.F2));
|
||||||
|
|
||||||
var compress = new MenuItem("Compress");
|
var compressItem = new MenuItem("Compress");
|
||||||
|
|
||||||
var properties = new MenuItem("Properties");
|
var propsItem = new MenuItem("Properties");
|
||||||
|
|
||||||
getItems().setAll(
|
getItems().setAll(
|
||||||
open,
|
new DemoMenuItem(),
|
||||||
new SeparatorMenuItem(),
|
new SeparatorMenuItem(),
|
||||||
cut,
|
openItem,
|
||||||
copy,
|
|
||||||
rename,
|
|
||||||
new SeparatorMenuItem(),
|
new SeparatorMenuItem(),
|
||||||
compress,
|
cutItem,
|
||||||
|
copyItem,
|
||||||
|
renameItem,
|
||||||
new SeparatorMenuItem(),
|
new SeparatorMenuItem(),
|
||||||
properties
|
compressItem,
|
||||||
|
new SeparatorMenuItem(),
|
||||||
|
propsItem
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private static class DemoMenuItem extends CustomMenuItem {
|
||||||
|
|
||||||
|
public DemoMenuItem() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
var label = new Label("This is a demo menu. None of \nthe options below are working.");
|
||||||
|
label.setWrapText(true);
|
||||||
|
label.setStyle("-fx-text-fill:-color-fg-muted");
|
||||||
|
|
||||||
|
setContent(label);
|
||||||
|
setHideOnClick(false);
|
||||||
|
getStyleClass().add("demo-menu-item");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ import static javafx.scene.control.TableColumn.SortType.ASCENDING;
|
|||||||
|
|
||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import atlantafx.base.theme.Tweaks;
|
import atlantafx.base.theme.Tweaks;
|
||||||
import atlantafx.sampler.util.Containers;
|
|
||||||
import atlantafx.sampler.util.HumanReadableFormat;
|
import atlantafx.sampler.util.HumanReadableFormat;
|
||||||
|
import atlantafx.sampler.util.NodeUtils;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.FileTime;
|
import java.nio.file.attribute.FileTime;
|
||||||
@ -23,7 +23,6 @@ import java.util.stream.Stream;
|
|||||||
import javafx.beans.property.SimpleLongProperty;
|
import javafx.beans.property.SimpleLongProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.css.PseudoClass;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.TableCell;
|
import javafx.scene.control.TableCell;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
@ -35,8 +34,6 @@ import javafx.scene.layout.Pane;
|
|||||||
|
|
||||||
final class TableDirectoryView extends AnchorPane implements DirectoryView {
|
final class TableDirectoryView extends AnchorPane implements DirectoryView {
|
||||||
|
|
||||||
private static final PseudoClass HIDDEN = PseudoClass.getPseudoClass("hidden");
|
|
||||||
private static final PseudoClass FOLDER = PseudoClass.getPseudoClass("folder");
|
|
||||||
private static final FileIconRepository REPO = new FileIconRepository();
|
private static final FileIconRepository REPO = new FileIconRepository();
|
||||||
private static final String UNKNOWN = "unknown";
|
private static final String UNKNOWN = "unknown";
|
||||||
|
|
||||||
@ -49,7 +46,7 @@ final class TableDirectoryView extends AnchorPane implements DirectoryView {
|
|||||||
|
|
||||||
getChildren().setAll(table);
|
getChildren().setAll(table);
|
||||||
getStyleClass().addAll("table-directory-view");
|
getStyleClass().addAll("table-directory-view");
|
||||||
Containers.setAnchors(table, Insets.EMPTY);
|
NodeUtils.setAnchors(table, Insets.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -152,8 +149,8 @@ final class TableDirectoryView extends AnchorPane implements DirectoryView {
|
|||||||
imageView.setImage(FileIconRepository.FOLDER);
|
imageView.setImage(FileIconRepository.FOLDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudoClassStateChanged(FOLDER, isDirectory);
|
pseudoClassStateChanged(Model.FOLDER, isDirectory);
|
||||||
getTableRow().pseudoClassStateChanged(HIDDEN, isFileHidden(path));
|
getTableRow().pseudoClassStateChanged(Model.HIDDEN, isFileHidden(path));
|
||||||
|
|
||||||
setGraphic(imageView);
|
setGraphic(imageView);
|
||||||
setText(filename);
|
setText(filename);
|
||||||
@ -195,10 +192,12 @@ final class TableDirectoryView extends AnchorPane implements DirectoryView {
|
|||||||
if (empty) {
|
if (empty) {
|
||||||
setText(null);
|
setText(null);
|
||||||
} else {
|
} else {
|
||||||
setText(fileTime != null
|
if (fileTime == null) {
|
||||||
? HumanReadableFormat.date(fileTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime())
|
setText(UNKNOWN);
|
||||||
: UNKNOWN
|
return;
|
||||||
);
|
}
|
||||||
|
var instant = fileTime.toInstant().atZone(ZoneId.systemDefault());
|
||||||
|
setText(HumanReadableFormat.date(instant.toLocalDateTime()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
.file-manager-showcase .bookmark-list .ikonli-font-icon {
|
#file-manager-showcase .table-directory-view .table-view {
|
||||||
-fx-icon-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-manager-showcase .breadcrumbs >.divider {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-manager-showcase .table-directory-view .table-view {
|
|
||||||
-color-header-bg: -color-bg-default;
|
-color-header-bg: -color-bg-default;
|
||||||
-color-cell-bg-selected: -color-accent-emphasis;
|
|
||||||
-color-cell-fg-selected: -color-fg-emphasis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setting opacity directly to the .table-cell or .table-row-cell
|
/* setting opacity directly to the .table-cell or .table-row-cell
|
||||||
leads to incorrect table row height calculation #javafx-bug */
|
leads to incorrect table row height calculation #javafx-bug */
|
||||||
.file-manager-showcase .table-row-cell:hidden >.table-cell > * {
|
#file-manager-showcase .table-row-cell:hidden >.table-cell > *,
|
||||||
-fx-opacity: 0.6;
|
#file-manager-showcase .tree-cell:hidden > * {
|
||||||
|
-fx-opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-menu-item:hover,
|
||||||
|
.demo-menu-item:focused,
|
||||||
|
.demo-menu-item:pressed {
|
||||||
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,9 @@ final class ColorThief {
|
|||||||
public static int[] getColor(BufferedImage source) {
|
public static int[] getColor(BufferedImage source) {
|
||||||
int[][] palette = getPalette(source, 5);
|
int[][] palette = getPalette(source, 5);
|
||||||
|
|
||||||
if (palette == null)
|
if (palette == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return palette[0];
|
return palette[0];
|
||||||
}
|
}
|
||||||
@ -43,8 +44,9 @@ final class ColorThief {
|
|||||||
public static int[][] getPalette(BufferedImage source, int colorCount) {
|
public static int[][] getPalette(BufferedImage source, int colorCount) {
|
||||||
MMCQ.ColorMap colorMap = getColorMap(source, colorCount);
|
MMCQ.ColorMap colorMap = getColorMap(source, colorCount);
|
||||||
|
|
||||||
if (colorMap == null)
|
if (colorMap == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return colorMap.palette();
|
return colorMap.palette();
|
||||||
}
|
}
|
||||||
@ -55,10 +57,12 @@ final class ColorThief {
|
|||||||
|
|
||||||
public static MMCQ.ColorMap getColorMap(BufferedImage sourceImage, int colorCount, int quality,
|
public static MMCQ.ColorMap getColorMap(BufferedImage sourceImage, int colorCount, int quality,
|
||||||
boolean ignoreWhite) {
|
boolean ignoreWhite) {
|
||||||
if (colorCount < 2 || colorCount > 256)
|
if (colorCount < 2 || colorCount > 256) {
|
||||||
throw new IllegalArgumentException("Specified colorCount must be between 2 and 256.");
|
throw new IllegalArgumentException("Specified colorCount must be between 2 and 256.");
|
||||||
if (quality < 1)
|
}
|
||||||
|
if (quality < 1) {
|
||||||
throw new IllegalArgumentException("Specified quality should be greater then 0.");
|
throw new IllegalArgumentException("Specified quality should be greater then 0.");
|
||||||
|
}
|
||||||
|
|
||||||
int[][] pixelArray = switch (sourceImage.getType()) {
|
int[][] pixelArray = switch (sourceImage.getType()) {
|
||||||
case TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR -> getPixelsFast(sourceImage, quality, ignoreWhite);
|
case TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR -> getPixelsFast(sourceImage, quality, ignoreWhite);
|
||||||
@ -202,7 +206,9 @@ final class ColorThief {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "r1: " + r1 + " / r2: " + r2 + " / g1: " + g1 + " / g2: " + g2 + " / b1: " + b1 + " / b2: " + b2;
|
return "r1: " + r1 + " / r2: " + r2
|
||||||
|
+ " / g1: " + g1 + " / g2: " + g2
|
||||||
|
+ " / b1: " + b1 + " / b2: " + b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int volume(boolean force) {
|
public int volume(boolean force) {
|
||||||
@ -260,10 +266,15 @@ final class ColorThief {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ntot > 0) {
|
if (ntot > 0) {
|
||||||
gAvg = new int[]{(rsum / ntot), (gsum / ntot), (bsum / ntot)};
|
gAvg = new int[] {
|
||||||
|
(rsum / ntot), (gsum / ntot), (bsum / ntot)
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
gAvg = new int[]{(MULT * (r1 + r2 + 1) / 2), (MULT * (g1 + g2 + 1) / 2),
|
gAvg = new int[] {
|
||||||
(MULT * (b1 + b2 + 1) / 2)};
|
(MULT * (r1 + r2 + 1) / 2),
|
||||||
|
(MULT * (g1 + g2 + 1) / 2),
|
||||||
|
(MULT * (b1 + b2 + 1) / 2)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ record MediaFile(File file) {
|
|||||||
// is costly and that instance is not even reusable.
|
// is costly and that instance is not even reusable.
|
||||||
public void readMetadata(Consumer<Metadata> callback) {
|
public void readMetadata(Consumer<Metadata> callback) {
|
||||||
var media = new Media(file.toURI().toString());
|
var media = new Media(file.toURI().toString());
|
||||||
|
System.out.println(file.toURI().toString());
|
||||||
var mediaPlayer = new MediaPlayer(media);
|
var mediaPlayer = new MediaPlayer(media);
|
||||||
|
|
||||||
// The media information is obtained asynchronously and so not necessarily
|
// The media information is obtained asynchronously and so not necessarily
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
package atlantafx.sampler.page.showcase.musicplayer;
|
package atlantafx.sampler.page.showcase.musicplayer;
|
||||||
|
|
||||||
|
import atlantafx.sampler.Resources;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
@ -14,6 +18,11 @@ import javafx.scene.paint.Color;
|
|||||||
|
|
||||||
final class Model {
|
final class Model {
|
||||||
|
|
||||||
|
private static final List<File> DEMO_FILES = List.of(
|
||||||
|
Paths.get(Resources.getResource("media/Beat Thee.mp3")).toFile(),
|
||||||
|
Paths.get(Resources.getResource("media/Study and Relax.mp3")).toFile()
|
||||||
|
);
|
||||||
|
|
||||||
private final ObservableList<MediaFile> playlist = FXCollections.observableArrayList();
|
private final ObservableList<MediaFile> playlist = FXCollections.observableArrayList();
|
||||||
private final ReadOnlyBooleanWrapper canGoBack = new ReadOnlyBooleanWrapper();
|
private final ReadOnlyBooleanWrapper canGoBack = new ReadOnlyBooleanWrapper();
|
||||||
private final ReadOnlyBooleanWrapper canGoForward = new ReadOnlyBooleanWrapper();
|
private final ReadOnlyBooleanWrapper canGoForward = new ReadOnlyBooleanWrapper();
|
||||||
@ -104,4 +113,9 @@ final class Model {
|
|||||||
reset();
|
reset();
|
||||||
playlist().clear();
|
playlist().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void playDemo() {
|
||||||
|
DEMO_FILES.forEach(f -> addFile(new MediaFile(f)));
|
||||||
|
play(new MediaFile(DEMO_FILES.get(0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ public class MusicPlayerPage extends ShowcasePage {
|
|||||||
|
|
||||||
public static final String NAME = "Music Player";
|
public static final String NAME = "Music Player";
|
||||||
public static final Set<String> SUPPORTED_MEDIA_TYPES = Set.of("mp3");
|
public static final Set<String> SUPPORTED_MEDIA_TYPES = Set.of("mp3");
|
||||||
private static final String STYLESHEET_URL = Objects.requireNonNull(
|
private static final String STYLESHEET_URL =
|
||||||
MusicPlayerPage.class.getResource("music-player.css")).toExternalForm();
|
Objects.requireNonNull(MusicPlayerPage.class.getResource("music-player.css")).toExternalForm();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -34,10 +34,9 @@ public class MusicPlayerPage extends ShowcasePage {
|
|||||||
var playerScreen = new PlayerScreen(model);
|
var playerScreen = new PlayerScreen(model);
|
||||||
|
|
||||||
var root = new BorderPane();
|
var root = new BorderPane();
|
||||||
|
root.setId("music-player-showcase");
|
||||||
root.setCenter(startScreen);
|
root.setCenter(startScreen);
|
||||||
|
|
||||||
root.getStylesheets().add(STYLESHEET_URL);
|
root.getStylesheets().add(STYLESHEET_URL);
|
||||||
root.getStyleClass().add("music-player-showcase");
|
|
||||||
|
|
||||||
model.playlist().addListener((ListChangeListener<MediaFile>) c -> {
|
model.playlist().addListener((ListChangeListener<MediaFile>) c -> {
|
||||||
if (model.playlist().size() > 0) {
|
if (model.playlist().size() > 0) {
|
||||||
@ -48,6 +47,9 @@ public class MusicPlayerPage extends ShowcasePage {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setWindowTitle("Music Player", new FontIcon(Feather.MUSIC));
|
setWindowTitle("Music Player", new FontIcon(Feather.MUSIC));
|
||||||
|
setAboutInfo("""
|
||||||
|
Simple music player that able to play MP3 files. Inspired by ©Amberol."""
|
||||||
|
);
|
||||||
setShowCaseContent(root);
|
setShowCaseContent(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +184,22 @@ final class PlayerPane extends VBox {
|
|||||||
setAlignment(CENTER);
|
setAlignment(CENTER);
|
||||||
setSpacing(5);
|
setSpacing(5);
|
||||||
setMinWidth(300);
|
setMinWidth(300);
|
||||||
getChildren().setAll(new Spacer(VERTICAL), new StackPane(coverImage), new Spacer(10, VERTICAL), trackTitle,
|
getChildren().setAll(
|
||||||
trackArtist, trackAlbum, new Spacer(20, VERTICAL), mediaControls, new Spacer(10, VERTICAL), timeSlider,
|
new Spacer(VERTICAL),
|
||||||
timeMarkersBox, new Spacer(10, VERTICAL), extraControls, new Spacer(VERTICAL));
|
new StackPane(coverImage),
|
||||||
|
new Spacer(10, VERTICAL),
|
||||||
|
trackTitle,
|
||||||
|
trackArtist,
|
||||||
|
trackAlbum,
|
||||||
|
new Spacer(20, VERTICAL),
|
||||||
|
mediaControls,
|
||||||
|
new Spacer(10, VERTICAL),
|
||||||
|
timeSlider,
|
||||||
|
timeMarkersBox,
|
||||||
|
new Spacer(10, VERTICAL),
|
||||||
|
extraControls,
|
||||||
|
new Spacer(VERTICAL)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
|
@ -31,20 +31,29 @@ final class PlayerScreen extends SplitPane {
|
|||||||
var domColor = Objects.equals(Color.TRANSPARENT, val)
|
var domColor = Objects.equals(Color.TRANSPARENT, val)
|
||||||
? Color.TRANSPARENT
|
? Color.TRANSPARENT
|
||||||
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 1);
|
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 1);
|
||||||
|
|
||||||
|
var domColor10 = Objects.equals(Color.TRANSPARENT, val)
|
||||||
|
? Color.TRANSPARENT
|
||||||
|
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.1);
|
||||||
|
|
||||||
var domColor20 = Objects.equals(Color.TRANSPARENT, val)
|
var domColor20 = Objects.equals(Color.TRANSPARENT, val)
|
||||||
? Color.TRANSPARENT
|
? Color.TRANSPARENT
|
||||||
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.2);
|
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.2);
|
||||||
|
|
||||||
var domColor50 = Objects.equals(Color.TRANSPARENT, val)
|
var domColor50 = Objects.equals(Color.TRANSPARENT, val)
|
||||||
? Color.TRANSPARENT
|
? Color.TRANSPARENT
|
||||||
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.5);
|
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.5);
|
||||||
|
|
||||||
var domColor70 = Objects.equals(Color.TRANSPARENT, val)
|
var domColor70 = Objects.equals(Color.TRANSPARENT, val)
|
||||||
? Color.TRANSPARENT
|
? Color.TRANSPARENT
|
||||||
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.7);
|
: Color.color(val.getRed(), val.getGreen(), val.getBlue(), 0.7);
|
||||||
|
|
||||||
setStyle("-color-dominant:" + toHexWithAlpha(domColor) + ";"
|
setStyle("-color-dominant:" + toHexWithAlpha(domColor) + ";"
|
||||||
|
+ "-color-dominant-10:" + toHexWithAlpha(domColor10) + ";"
|
||||||
+ "-color-dominant-20:" + toHexWithAlpha(domColor20) + ";"
|
+ "-color-dominant-20:" + toHexWithAlpha(domColor20) + ";"
|
||||||
+ "-color-dominant-50:" + toHexWithAlpha(domColor50) + ";"
|
+ "-color-dominant-50:" + toHexWithAlpha(domColor50) + ";"
|
||||||
+ "-color-dominant-70:" + toHexWithAlpha(domColor70) + ";"
|
+ "-color-dominant-70:" + toHexWithAlpha(domColor70) + ";"
|
||||||
+ "-color-dominant-border:" + toHexWithAlpha(domColor70) + ";"
|
+ "-color-dominant-border:" + toHexWithAlpha(domColor50) + ";"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,6 @@ final class StartScreen extends BorderPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createView() {
|
private void createView() {
|
||||||
var jumboIcon = new FontIcon(Feather.MUSIC);
|
|
||||||
|
|
||||||
var noteText = new TextFlow(new Text(
|
var noteText = new TextFlow(new Text(
|
||||||
"Select a file or a folder."
|
"Select a file or a folder."
|
||||||
));
|
));
|
||||||
@ -54,10 +52,17 @@ final class StartScreen extends BorderPane {
|
|||||||
addFileBtn.setPrefWidth(150);
|
addFileBtn.setPrefWidth(150);
|
||||||
addFileBtn.setOnAction(e -> addFile());
|
addFileBtn.setOnAction(e -> addFile());
|
||||||
|
|
||||||
var controls = new VBox(10, addFolderBtn, addFileBtn);
|
var addDemoBtn = new Button("Play Demo");
|
||||||
|
addDemoBtn.getStyleClass().add(Styles.SUCCESS);
|
||||||
|
addDemoBtn.setPrefWidth(150);
|
||||||
|
addDemoBtn.setOnAction(e -> model.playDemo());
|
||||||
|
|
||||||
|
var controls = new VBox(10, addFolderBtn, addFileBtn, addDemoBtn);
|
||||||
controls.setAlignment(Pos.CENTER);
|
controls.setAlignment(Pos.CENTER);
|
||||||
controls.setFillWidth(true);
|
controls.setFillWidth(true);
|
||||||
|
|
||||||
|
var jumboIcon = new FontIcon(Feather.MUSIC);
|
||||||
|
|
||||||
var content = new VBox(30, jumboIcon, noteText, controls);
|
var content = new VBox(30, jumboIcon, noteText, controls);
|
||||||
content.getStyleClass().add("content");
|
content.getStyleClass().add("content");
|
||||||
content.setAlignment(Pos.CENTER);
|
content.setAlignment(Pos.CENTER);
|
||||||
|
@ -1,50 +1,76 @@
|
|||||||
/** SPDX-License-Identifier: MIT */
|
/** SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
.music-player-showcase > .start-screen {
|
#music-player-showcase > .start-screen > .content > .ikonli-font-icon {
|
||||||
-fx-border-color: -color-border-muted;
|
|
||||||
-fx-border-width: 1;
|
|
||||||
}
|
|
||||||
.music-player-showcase > .start-screen > .content > .ikonli-font-icon {
|
|
||||||
-fx-icon-color: -color-fg-muted;
|
-fx-icon-color: -color-fg-muted;
|
||||||
-fx-fill: -color-fg-muted;
|
-fx-fill: -color-fg-muted;
|
||||||
-fx-icon-size: 64px;
|
-fx-icon-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.music-player-showcase > .player-screen {
|
#music-player-showcase > .player-screen {
|
||||||
-fx-border-color: -color-border-muted;
|
/* default colors (when no artwork found) */
|
||||||
-fx-border-width: 1;
|
|
||||||
-color-dominant: transparent;
|
-color-dominant: transparent;
|
||||||
|
-color-dominant-10: transparent;
|
||||||
-color-dominant-20: transparent;
|
-color-dominant-20: transparent;
|
||||||
-color-dominant-50: transparent;
|
-color-dominant-50: transparent;
|
||||||
-color-dominant-70: transparent;
|
-color-dominant-70: transparent;
|
||||||
-color-dominant-border: -color-border-muted;
|
-color-dominant-border: -color-border-default;
|
||||||
|
|
||||||
|
-fx-background-color: radial-gradient(radius 100%, -color-dominant-20, -color-dominant-50);
|
||||||
}
|
}
|
||||||
.music-player-showcase > .player-screen > * > .player {
|
|
||||||
-fx-background-color: radial-gradient(radius 100%, -color-dominant-50, -color-dominant-20);
|
#music-player-showcase > .player-screen > .split-pane-divider {
|
||||||
}
|
|
||||||
.music-player-showcase > .player-screen > * > .player > .media-controls > .play > .ikonli-font-icon {
|
|
||||||
-fx-icon-size: 32px;
|
|
||||||
}
|
|
||||||
.music-player-showcase > .player-screen > .split-pane-divider {
|
|
||||||
-color-split-divider: -color-dominant-border;
|
-color-split-divider: -color-dominant-border;
|
||||||
-color-split-grabber: -color-dominant-border;
|
-color-split-grabber: -color-dominant-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
.music-player-showcase > .player-screen > * > .playlist {
|
/* == PLAYER == */
|
||||||
-fx-background-color: radial-gradient(radius 100%, -color-dominant-20, -color-dominant-50);
|
|
||||||
|
#music-player-showcase .player > .media-controls > .play > .ikonli-font-icon {
|
||||||
|
-fx-icon-size: 32px;
|
||||||
}
|
}
|
||||||
.music-player-showcase > .player-screen > * > .playlist > .controls {
|
|
||||||
|
#music-player-showcase .player .button {
|
||||||
|
-color-button-bg: -color-dominant-10;
|
||||||
|
-color-button-bg-hover: -color-dominant-20;
|
||||||
|
-color-button-bg-focused: -color-dominant-10;
|
||||||
|
-color-button-bg-pressed: -color-dominant-10;
|
||||||
|
-color-button-border: transparent;
|
||||||
|
-color-button-border-hover: transparent;
|
||||||
|
-color-button-border-focused: transparent;
|
||||||
|
-color-button-border-pressed: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#music-player-showcase .player .slider {
|
||||||
|
-color-slider-track: -color-dominant-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* == PLAYLIST == */
|
||||||
|
|
||||||
|
#music-player-showcase .playlist > .controls {
|
||||||
-fx-border-color: -color-dominant-border;
|
-fx-border-color: -color-dominant-border;
|
||||||
-fx-border-width: 0 0 0.75px 0;
|
-fx-border-width: 0 0 0.75px 0;
|
||||||
}
|
}
|
||||||
.music-player-showcase > .player-screen > * > .playlist > .controls > .button {
|
|
||||||
-color-button-bg-hover: transparent;
|
#music-player-showcase .playlist > .controls > .button {
|
||||||
|
-color-button-bg-hover: -color-dominant-20;
|
||||||
-color-button-bg-focused: transparent;
|
-color-button-bg-focused: transparent;
|
||||||
-color-button-bg-pressed: transparent;
|
-color-button-bg-pressed: transparent;
|
||||||
|
-color-button-border: transparent;
|
||||||
|
-color-button-border-hover: transparent;
|
||||||
|
-color-button-border-focused: transparent;
|
||||||
|
-color-button-border-pressed: transparent;
|
||||||
}
|
}
|
||||||
.music-player-showcase > .player-screen > * > .playlist > .list-view .list-cell {
|
|
||||||
|
#music-player-showcase .playlist .list-cell {
|
||||||
-color-cell-bg: transparent;
|
-color-cell-bg: transparent;
|
||||||
-color-cell-bg-selected: transparent;
|
-color-cell-bg-selected: transparent;
|
||||||
|
-color-cell-bg-selected-focused: transparent;
|
||||||
-color-cell-border: transparent;
|
-color-cell-border: transparent;
|
||||||
-fx-cell-size: 4em;
|
-fx-cell-size: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#music-player-showcase .playlist .list-cell:filled:hover {
|
||||||
|
-color-cell-bg: -color-dominant-20;
|
||||||
|
-color-cell-bg-selected: -color-dominant-20;
|
||||||
|
-color-cell-bg-selected-focused: -color-dominant-20;
|
||||||
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
|
||||||
|
|
||||||
package atlantafx.sampler.util;
|
|
||||||
|
|
||||||
import static javafx.scene.layout.Region.USE_COMPUTED_SIZE;
|
|
||||||
import static javafx.scene.layout.Region.USE_PREF_SIZE;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
|
||||||
import javafx.scene.layout.Priority;
|
|
||||||
import javafx.scene.layout.Region;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public final class Containers {
|
|
||||||
|
|
||||||
public static final ColumnConstraints H_GROW_NEVER = columnConstraints(Priority.NEVER);
|
|
||||||
|
|
||||||
public static void setAnchors(Node node, Insets insets) {
|
|
||||||
if (insets.getTop() >= 0) {
|
|
||||||
AnchorPane.setTopAnchor(node, insets.getTop());
|
|
||||||
}
|
|
||||||
if (insets.getRight() >= 0) {
|
|
||||||
AnchorPane.setRightAnchor(node, insets.getRight());
|
|
||||||
}
|
|
||||||
if (insets.getBottom() >= 0) {
|
|
||||||
AnchorPane.setBottomAnchor(node, insets.getBottom());
|
|
||||||
}
|
|
||||||
if (insets.getLeft() >= 0) {
|
|
||||||
AnchorPane.setLeftAnchor(node, insets.getLeft());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setScrollConstraints(ScrollPane scrollPane,
|
|
||||||
ScrollPane.ScrollBarPolicy vbarPolicy, boolean fitHeight,
|
|
||||||
ScrollPane.ScrollBarPolicy hbarPolicy, boolean fitWidth) {
|
|
||||||
scrollPane.setVbarPolicy(vbarPolicy);
|
|
||||||
scrollPane.setFitToHeight(fitHeight);
|
|
||||||
scrollPane.setHbarPolicy(hbarPolicy);
|
|
||||||
scrollPane.setFitToWidth(fitWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ColumnConstraints columnConstraints(Priority hgrow) {
|
|
||||||
return columnConstraints(USE_COMPUTED_SIZE, hgrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ColumnConstraints columnConstraints(double minWidth, Priority hgrow) {
|
|
||||||
double maxWidth = hgrow == Priority.ALWAYS ? Double.MAX_VALUE : USE_PREF_SIZE;
|
|
||||||
ColumnConstraints constraints = new ColumnConstraints(minWidth, USE_COMPUTED_SIZE, maxWidth);
|
|
||||||
constraints.setHgrow(hgrow);
|
|
||||||
return constraints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void usePrefWidth(Region region) {
|
|
||||||
region.setMinWidth(USE_PREF_SIZE);
|
|
||||||
region.setMaxWidth(USE_PREF_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void usePrefHeight(Region region) {
|
|
||||||
region.setMinHeight(USE_PREF_SIZE);
|
|
||||||
region.setMaxHeight(USE_PREF_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT */
|
|
||||||
|
|
||||||
package atlantafx.sampler.util;
|
|
||||||
|
|
||||||
import static atlantafx.base.theme.Styles.BUTTON_ICON;
|
|
||||||
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import org.kordamp.ikonli.Ikon;
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public final class Controls {
|
|
||||||
|
|
||||||
public static Button iconButton(Ikon icon, boolean disable) {
|
|
||||||
return button("", icon, disable, BUTTON_ICON);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Button button(String text, Ikon icon, boolean disable, String... styleClasses) {
|
|
||||||
var button = new Button(text);
|
|
||||||
if (icon != null) {
|
|
||||||
button.setGraphic(new FontIcon(icon));
|
|
||||||
}
|
|
||||||
button.setDisable(disable);
|
|
||||||
button.getStyleClass().addAll(styleClasses);
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,10 +3,13 @@
|
|||||||
package atlantafx.sampler.util;
|
package atlantafx.sampler.util;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
|
||||||
public final class NodeUtils {
|
public final class NodeUtils {
|
||||||
|
|
||||||
@ -15,6 +18,30 @@ public final class NodeUtils {
|
|||||||
node.setManaged(on);
|
node.setManaged(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setAnchors(Node node, Insets insets) {
|
||||||
|
if (insets.getTop() >= 0) {
|
||||||
|
AnchorPane.setTopAnchor(node, insets.getTop());
|
||||||
|
}
|
||||||
|
if (insets.getRight() >= 0) {
|
||||||
|
AnchorPane.setRightAnchor(node, insets.getRight());
|
||||||
|
}
|
||||||
|
if (insets.getBottom() >= 0) {
|
||||||
|
AnchorPane.setBottomAnchor(node, insets.getBottom());
|
||||||
|
}
|
||||||
|
if (insets.getLeft() >= 0) {
|
||||||
|
AnchorPane.setLeftAnchor(node, insets.getLeft());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setScrollConstraints(ScrollPane scrollPane,
|
||||||
|
ScrollPane.ScrollBarPolicy vbarPolicy, boolean fitHeight,
|
||||||
|
ScrollPane.ScrollBarPolicy hbarPolicy, boolean fitWidth) {
|
||||||
|
scrollPane.setVbarPolicy(vbarPolicy);
|
||||||
|
scrollPane.setFitToHeight(fitHeight);
|
||||||
|
scrollPane.setHbarPolicy(hbarPolicy);
|
||||||
|
scrollPane.setFitToWidth(fitWidth);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isDoubleClick(MouseEvent e) {
|
public static boolean isDoubleClick(MouseEvent e) {
|
||||||
return e.getButton().equals(MouseButton.PRIMARY) && e.getClickCount() == 2;
|
return e.getButton().equals(MouseButton.PRIMARY) && e.getClickCount() == 2;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
.showcase-page {
|
.showcase-page {
|
||||||
|
-fx-background-color: -color-bg-default;
|
||||||
|
|
||||||
>.window {
|
>.window {
|
||||||
-fx-border-color: -color-accent-emphasis;
|
-fx-border-color: -color-accent-emphasis;
|
||||||
@ -44,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#overview {
|
#blueprints {
|
||||||
-fx-background-color: -color-bg-inset;
|
-fx-background-color: -color-bg-inset;
|
||||||
|
|
||||||
.sample {
|
.sample {
|
||||||
|
BIN
sampler/src/main/resources/atlantafx/sampler/images/papirus/places/folder-paleorange.png
Normal file
After Width: | Height: | Size: 2.8 KiB |