Support icon color and add icons page
This commit is contained in:
parent
c547b7231b
commit
0eee144d26
@ -5,6 +5,7 @@ import atlantafx.base.controls.Spacer;
|
|||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import atlantafx.sampler.page.Page;
|
import atlantafx.sampler.page.Page;
|
||||||
import atlantafx.sampler.page.components.*;
|
import atlantafx.sampler.page.components.*;
|
||||||
|
import atlantafx.sampler.page.general.IconsPage;
|
||||||
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;
|
||||||
@ -170,6 +171,7 @@ class Sidebar extends StackPane {
|
|||||||
caption("GENERAL"),
|
caption("GENERAL"),
|
||||||
navLink(ThemePage.NAME, ThemePage.class),
|
navLink(ThemePage.NAME, ThemePage.class),
|
||||||
navLink(TypographyPage.NAME, TypographyPage.class),
|
navLink(TypographyPage.NAME, TypographyPage.class),
|
||||||
|
navLink(IconsPage.NAME, IconsPage.class),
|
||||||
caption("COMPONENTS"),
|
caption("COMPONENTS"),
|
||||||
navLink(OverviewPage.NAME, OverviewPage.class),
|
navLink(OverviewPage.NAME, OverviewPage.class),
|
||||||
navLink(InputGroupPage.NAME, InputGroupPage.class),
|
navLink(InputGroupPage.NAME, InputGroupPage.class),
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
package atlantafx.sampler.page.general;
|
||||||
|
|
||||||
|
import atlantafx.base.theme.Tweaks;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import org.kordamp.ikonli.Ikon;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static atlantafx.base.theme.Styles.TEXT_SMALL;
|
||||||
|
|
||||||
|
public class IconBrowser extends TableView<List<Ikon>> {
|
||||||
|
|
||||||
|
static final int FILTER_LEN = 2;
|
||||||
|
|
||||||
|
private final int colNum;
|
||||||
|
private final List<Ikon> icons;
|
||||||
|
private final SimpleStringProperty filter = new SimpleStringProperty();
|
||||||
|
|
||||||
|
public IconBrowser(int colNum, List<Ikon> icons) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (colNum <= 0) {
|
||||||
|
throw new IllegalArgumentException("Column count must be greater than 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icons == null || icons.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Icon list cannot be null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.colNum = colNum;
|
||||||
|
this.icons = icons;
|
||||||
|
|
||||||
|
filterProperty().addListener((obs, old, val) -> updateData(val));
|
||||||
|
|
||||||
|
initTable();
|
||||||
|
updateData(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty filterProperty() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTable() {
|
||||||
|
for (int i = 0; i < colNum; i++) {
|
||||||
|
var col = new TableColumn<List<Ikon>, Ikon>("col" + i);
|
||||||
|
final int colIndex = i;
|
||||||
|
col.setCellValueFactory(cb -> {
|
||||||
|
var row = cb.getValue();
|
||||||
|
var item = row.size() > colIndex ? row.get(colIndex) : null;
|
||||||
|
return new SimpleObjectProperty<>(item);
|
||||||
|
});
|
||||||
|
col.setCellFactory(cb -> new FontIconCell());
|
||||||
|
col.getStyleClass().add(Tweaks.ALIGN_CENTER);
|
||||||
|
getColumns().add(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
getSelectionModel().setCellSelectionEnabled(true);
|
||||||
|
getStyleClass().add("icon-browser");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateData(String filterString) {
|
||||||
|
var displayedIcons = filterString == null || filterString.isBlank() || filterString.length() < FILTER_LEN
|
||||||
|
? icons
|
||||||
|
: icons.stream().filter(icon -> containsString(icon.getDescription(), filterString)).toList();
|
||||||
|
|
||||||
|
var data = partitionList(displayedIcons, colNum);
|
||||||
|
getItems().setAll(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> Collection<List<T>> partitionList(List<T> list, int size) {
|
||||||
|
List<List<T>> partitions = new ArrayList<>();
|
||||||
|
if (list.size() == 0) {
|
||||||
|
return partitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = list.size();
|
||||||
|
int numOfPartitions = length / size + ((length % size == 0) ? 0 : 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < numOfPartitions; i++) {
|
||||||
|
int from = i * size;
|
||||||
|
int to = Math.min((i * size + size), length);
|
||||||
|
partitions.add(list.subList(from, to));
|
||||||
|
}
|
||||||
|
return partitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsString(String s1, String s2) {
|
||||||
|
return s1.toLowerCase(Locale.ROOT).contains(s2.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public static class FontIconCell extends TableCell<List<Ikon>, Ikon> {
|
||||||
|
|
||||||
|
private final Label root = new Label();
|
||||||
|
private final FontIcon fontIcon = new FontIcon();
|
||||||
|
|
||||||
|
public FontIconCell() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
root.setContentDisplay(ContentDisplay.TOP);
|
||||||
|
root.setGraphic(fontIcon);
|
||||||
|
root.setGraphicTextGap(10);
|
||||||
|
root.getStyleClass().addAll("icon-label", TEXT_SMALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Ikon icon, boolean empty) {
|
||||||
|
super.updateItem(icon, empty);
|
||||||
|
|
||||||
|
if (icon == null) {
|
||||||
|
setGraphic(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.setText(icon.getDescription());
|
||||||
|
fontIcon.setIconCode(icon);
|
||||||
|
setGraphic(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
package atlantafx.sampler.page.general;
|
||||||
|
|
||||||
|
import atlantafx.base.controls.CustomTextField;
|
||||||
|
import atlantafx.base.theme.Styles;
|
||||||
|
import atlantafx.sampler.page.AbstractPage;
|
||||||
|
import atlantafx.sampler.page.SampleBlock;
|
||||||
|
import atlantafx.sampler.theme.CSSFragment;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.text.TextFlow;
|
||||||
|
import org.kordamp.ikonli.Ikon;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
import org.kordamp.ikonli.javafx.StackedFontIcon;
|
||||||
|
import org.kordamp.ikonli.material2.Material2AL;
|
||||||
|
import org.kordamp.ikonli.material2.Material2MZ;
|
||||||
|
import org.kordamp.ikonli.material2.Material2OutlinedAL;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static atlantafx.sampler.page.SampleBlock.BLOCK_HGAP;
|
||||||
|
import static atlantafx.sampler.page.SampleBlock.BLOCK_VGAP;
|
||||||
|
import static atlantafx.sampler.util.Controls.hyperlink;
|
||||||
|
|
||||||
|
public class IconsPage extends AbstractPage {
|
||||||
|
|
||||||
|
public static final String NAME = "Icons";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return NAME; }
|
||||||
|
|
||||||
|
public IconsPage() {
|
||||||
|
super();
|
||||||
|
createView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createView() {
|
||||||
|
var headerText = new TextFlow(
|
||||||
|
new Text("AtlantaFX supports "),
|
||||||
|
hyperlink("Ikonli", URI.create("https://kordamp.org/ikonli")),
|
||||||
|
new Text(" iconic fonts that can be used together with some JavaFX components.")
|
||||||
|
);
|
||||||
|
|
||||||
|
var browserText = new TextFlow(
|
||||||
|
new Text("There's a variety of icon packs. Sampler app uses "),
|
||||||
|
hyperlink("Material Icons", URI.create("https://kordamp.org/ikonli/cheat-sheet-material2.html")),
|
||||||
|
new Text(" you can preview below.")
|
||||||
|
);
|
||||||
|
|
||||||
|
var filterText = new CustomTextField();
|
||||||
|
filterText.setLeft(new FontIcon(Material2MZ.SEARCH));
|
||||||
|
filterText.setPrefWidth(300);
|
||||||
|
|
||||||
|
var filterBox = new HBox(filterText);
|
||||||
|
filterBox.setAlignment(Pos.CENTER);
|
||||||
|
|
||||||
|
var icons = new ArrayList<Ikon>();
|
||||||
|
icons.addAll(Arrays.asList(Material2AL.values()));
|
||||||
|
icons.addAll(Arrays.asList(Material2MZ.values()));
|
||||||
|
|
||||||
|
var iconBrowser = new IconBrowser(5, icons);
|
||||||
|
VBox.setVgrow(iconBrowser, Priority.ALWAYS);
|
||||||
|
iconBrowser.filterProperty().bind(filterText.textProperty());
|
||||||
|
|
||||||
|
setUserContent(new VBox(
|
||||||
|
PAGE_VGAP,
|
||||||
|
headerText,
|
||||||
|
expandingHBox(colorSample(), stackingSample()),
|
||||||
|
browserText,
|
||||||
|
filterBox,
|
||||||
|
iconBrowser
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SampleBlock colorSample() {
|
||||||
|
var accentIcon = new FontIcon(Material2MZ.THUMB_UP);
|
||||||
|
accentIcon.getStyleClass().add(Styles.ACCENT);
|
||||||
|
|
||||||
|
var successIcon = new FontIcon(Material2MZ.THUMB_UP);
|
||||||
|
successIcon.getStyleClass().add(Styles.SUCCESS);
|
||||||
|
|
||||||
|
var warningIcon = new FontIcon(Material2MZ.THUMB_UP);
|
||||||
|
warningIcon.getStyleClass().add(Styles.WARNING);
|
||||||
|
|
||||||
|
var dangerIcon = new FontIcon(Material2MZ.THUMB_UP);
|
||||||
|
dangerIcon.getStyleClass().add(Styles.DANGER);
|
||||||
|
|
||||||
|
var content = new VBox(
|
||||||
|
BLOCK_VGAP,
|
||||||
|
new Label("You can also use pseudo-classes to set icon color."),
|
||||||
|
new HBox(BLOCK_HGAP, accentIcon, successIcon, warningIcon, dangerIcon)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new SampleBlock("Colors", content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SampleBlock stackingSample() {
|
||||||
|
var outerIcon1 = new FontIcon(Material2OutlinedAL.BLOCK);
|
||||||
|
outerIcon1.getStyleClass().add("outer-icon");
|
||||||
|
|
||||||
|
var innerIcon1 = new FontIcon(Material2MZ.PHOTO_CAMERA);
|
||||||
|
innerIcon1.getStyleClass().add("inner-icon");
|
||||||
|
|
||||||
|
var stackIcon1 = new StackedFontIcon();
|
||||||
|
stackIcon1.getChildren().addAll(innerIcon1, outerIcon1);
|
||||||
|
new CSSFragment("""
|
||||||
|
.stacked-ikonli-font-icon > .outer-icon {
|
||||||
|
-fx-icon-size: 48px;
|
||||||
|
-fx-icon-color: -color-danger-emphasis;
|
||||||
|
}
|
||||||
|
.stacked-ikonli-font-icon > .inner-icon {
|
||||||
|
-fx-icon-size: 24px;
|
||||||
|
}
|
||||||
|
""").addTo(stackIcon1);
|
||||||
|
|
||||||
|
var outerIcon2 = new FontIcon(Material2OutlinedAL.CHECK_BOX_OUTLINE_BLANK);
|
||||||
|
outerIcon2.getStyleClass().add("outer-icon");
|
||||||
|
|
||||||
|
var innerIcon2 = new FontIcon(Material2AL.LOCK);
|
||||||
|
innerIcon2.getStyleClass().add("inner-icon");
|
||||||
|
|
||||||
|
var stackIcon2 = new StackedFontIcon();
|
||||||
|
stackIcon2.getChildren().addAll(outerIcon2, innerIcon2);
|
||||||
|
new CSSFragment("""
|
||||||
|
.stacked-ikonli-font-icon > .outer-icon {
|
||||||
|
-fx-icon-size: 48px;
|
||||||
|
}
|
||||||
|
.stacked-ikonli-font-icon > .inner-icon {
|
||||||
|
-fx-icon-size: 24px;
|
||||||
|
}
|
||||||
|
""").addTo(stackIcon2);
|
||||||
|
|
||||||
|
var content = new HBox(BLOCK_HGAP, stackIcon1, stackIcon2);
|
||||||
|
|
||||||
|
return new SampleBlock("Stacking Icons", content);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
.icon-browser {
|
||||||
|
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
-color-cell-border: transparent;
|
||||||
|
|
||||||
|
>.column-header-background {
|
||||||
|
-fx-max-height: 0;
|
||||||
|
-fx-pref-height: 0;
|
||||||
|
-fx-min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row-cell {
|
||||||
|
-fx-cell-size: 80px;
|
||||||
|
|
||||||
|
.icon-label {
|
||||||
|
-fx-padding: 10px;
|
||||||
|
-fx-cursor: hand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon {
|
||||||
|
-fx-icon-size: 36px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
@use "html-editor-fix"
|
@use "html-editor-fix";
|
||||||
|
@use "icon-browser";
|
@ -3,7 +3,8 @@
|
|||||||
@use "../settings/config" as cfg;
|
@use "../settings/config" as cfg;
|
||||||
@use "../settings/effects";
|
@use "../settings/effects";
|
||||||
|
|
||||||
@each $level, $radius in cfg.$elevation {
|
@each $level,
|
||||||
|
$radius in cfg.$elevation {
|
||||||
.elevated-#{$level} {
|
.elevated-#{$level} {
|
||||||
@include effects.shadow(cfg.$elevation-color, $radius);
|
@include effects.shadow(cfg.$elevation-color, $radius);
|
||||||
}
|
}
|
||||||
@ -12,3 +13,47 @@
|
|||||||
.interactive:hover {
|
.interactive:hover {
|
||||||
@include effects.shadow(cfg.$elevation-color, cfg.$elevation-interactive);
|
@include effects.shadow(cfg.$elevation-color, cfg.$elevation-interactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Ikonli //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
.ikonli-font-icon.accent {
|
||||||
|
-fx-fill: -color-accent-emphasis;
|
||||||
|
-fx-icon-color: -color-accent-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon.success {
|
||||||
|
-fx-fill: -color-success-emphasis;
|
||||||
|
-fx-icon-color: -color-success-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon.warning {
|
||||||
|
-fx-fill: -color-warning-emphasis;
|
||||||
|
-fx-icon-color: -color-warning-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon.danger {
|
||||||
|
-fx-fill: -color-danger-emphasis;
|
||||||
|
-fx-icon-color: -color-danger-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon:accent {
|
||||||
|
-fx-fill: -color-accent-emphasis;
|
||||||
|
-fx-icon-color: -color-accent-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon:success {
|
||||||
|
-fx-fill: -color-success-emphasis;
|
||||||
|
-fx-icon-color: -color-success-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon:warning {
|
||||||
|
-fx-fill: -color-warning-emphasis;
|
||||||
|
-fx-icon-color: -color-warning-emphasis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ikonli-font-icon:danger {
|
||||||
|
-fx-fill: -color-danger-emphasis;
|
||||||
|
-fx-icon-color: -color-danger-emphasis;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user