diff --git a/pom.xml b/pom.xml
index 81585b0..0c9f072 100644
--- a/pom.xml
+++ b/pom.xml
@@ -133,12 +133,12 @@
com.imyeyu.fx
timi-fx
- 0.0.5
+ 0.0.6
com.imyeyu.fx.icon
timi-fx-icon
- 0.0.2
+ 0.0.3
com.imyeyu.lang
diff --git a/src/main/java/com/imyeyu/fx/ui/ScreenIdentify.java b/src/main/java/com/imyeyu/fx/ui/ScreenIdentify.java
index 3298d33..1cf672a 100644
--- a/src/main/java/com/imyeyu/fx/ui/ScreenIdentify.java
+++ b/src/main/java/com/imyeyu/fx/ui/ScreenIdentify.java
@@ -1,6 +1,6 @@
package com.imyeyu.fx.ui;
-import com.imyeyu.fx.utils.ScreenFX;
+import com.imyeyu.fx.utils.screen.Screens;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
@@ -66,7 +66,7 @@ public class ScreenIdentify extends Stage implements TimiFXUI {
public void showIdentify() {
show();
- List screens = ScreenFX.SCREENS;
+ List screens = Screens.all();
for (int i = 0; i < screens.size(); i++) {
showingIdentifyList.add(new Identify(screens.get(i), i));
}
@@ -111,7 +111,7 @@ public class ScreenIdentify extends Stage implements TimiFXUI {
getContent().setAll(text);
getScene().setFill(BLACK);
- getScene().getStylesheets().addAll(CSS_STYLE, CSS_FONT);
+ TimiFXUI.applyStyle(getScene());
sizeToScene();
}
}
diff --git a/src/main/java/com/imyeyu/fx/ui/TimiFXUI.java b/src/main/java/com/imyeyu/fx/ui/TimiFXUI.java
index 6d073e1..5ae8306 100644
--- a/src/main/java/com/imyeyu/fx/ui/TimiFXUI.java
+++ b/src/main/java/com/imyeyu/fx/ui/TimiFXUI.java
@@ -1,18 +1,25 @@
package com.imyeyu.fx.ui;
-import com.imyeyu.fx.utils.BgFill;
-import com.imyeyu.fx.utils.BorderStroke;
+import com.imyeyu.fx.utils.BorderBuilder;
+import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
+import com.imyeyu.fx.utils.layout.Layout;
import com.imyeyu.lang.multi.ResourcesMultilingual;
+import com.sun.javafx.css.StyleManager;
import javafx.geometry.Insets;
+import javafx.geometry.VPos;
import javafx.scene.Node;
+import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.Background;
import javafx.scene.layout.Border;
+import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
+import java.util.Objects;
+
/**
* @author 夜雨
* @version 2024-04-13 14:18
@@ -22,14 +29,55 @@ public interface TimiFXUI {
/** 静态资源路径 */
String RESOURCE = "/timifx/";
+ String RESOURCE_STYLE = RESOURCE + "/style";
+
/** 样式文件 */
- String CSS_STYLE = RESOURCE + "style/style.css";
+ String CSS_STYLE = resource("style/style.css");
+
+ /** 控件默认样式文件 */
+ String CSS_USER_AGENT = resource("style/user-agent.css");
/** 全局字体替换 */
- String CSS_FONT = RESOURCE + "style/font.css";
+ String CSS_FONT = resource("style/font.css");
ResourcesMultilingual MULTILINGUAL = new ResourcesMultilingual();
+ /**
+ * 获取静态资源路径
+ *
+ * @param path 相对静态资源目录的路径
+ *
+ * @return 静态资源绝对路径
+ */
+ private static String resource(String path) {
+ return Objects.requireNonNull(TimiFXUI.class.getResource(RESOURCE + path)).toExternalForm();
+ }
+
+ /**
+ * 应用全局样式
+ *
+ * @param scene 场景
+ * @param stylesheets 追加的样式表
+ */
+ static void applyStyle(Scene scene, String... stylesheets) {
+ if (!Boolean.TRUE.equals(scene.getProperties().get(CSS_USER_AGENT))) {
+ StyleManager.getInstance().addUserAgentStylesheet(scene, CSS_USER_AGENT);
+ scene.getProperties().put(CSS_USER_AGENT, true);
+ }
+ if (!scene.getStylesheets().contains(CSS_STYLE)) {
+ scene.getStylesheets().add(CSS_STYLE);
+ }
+ if (!scene.getStylesheets().contains(CSS_FONT)) {
+ scene.getStylesheets().add(CSS_FONT);
+ }
+ for (String stylesheet : stylesheets) {
+ if (!scene.getStylesheets().contains(stylesheet)) {
+ scene.getStylesheets().add(stylesheet);
+ }
+ }
+ }
+
+
/**
*
*
@@ -122,58 +170,58 @@ public interface TimiFXUI {
interface Stroke {
/** 透明边框 */
- Border TP = new BorderStroke(Colorful.TRANSPARENT).build();
+ Border TP = BorderBuilder.solid(Colorful.TRANSPARENT).build();
/** 默认边框 */
- Border DEFAULT = new BorderStroke(Colorful.BORDER).build();
+ Border DEFAULT = BorderBuilder.solid(Colorful.BORDER).build();
/** 禁用边框 */
- Border DISABLE = new BorderStroke("#E1E1E1").build();
+ Border DISABLE = BorderBuilder.solid("#E1E1E1").build();
/** 聚焦边框 */
- Border FOCUSED = new BorderStroke(Colorful.BORDER).build();
+ Border FOCUSED = BorderBuilder.solid(Colorful.BORDER).build();
/** 上边框 */
- Border TOP = new BorderStroke(Colorful.BORDER).top().build();
+ Border TOP = BorderBuilder.solid(Colorful.BORDER).top().build();
/** 左边框 */
- Border LEFT = new BorderStroke(Colorful.BORDER).left().build();
+ Border LEFT = BorderBuilder.solid(Colorful.BORDER).left().build();
/** 右边框 */
- Border RIGHT = new BorderStroke(Colorful.BORDER).right().build();
+ Border RIGHT = BorderBuilder.solid(Colorful.BORDER).right().build();
/** 下边框 */
- Border BOTTOM = new BorderStroke(Colorful.BORDER).bottom().build();
+ Border BOTTOM = BorderBuilder.solid(Colorful.BORDER).bottom().build();
/** 除了上边框 */
- Border EX_TOP = new BorderStroke(Colorful.BORDER).exTop().build();
+ Border EX_TOP = BorderBuilder.solid(Colorful.BORDER).exceptTop().build();
/** 除了左边框 */
- Border EX_LEFT = new BorderStroke(Colorful.BORDER).exLeft().build();
+ Border EX_LEFT = BorderBuilder.solid(Colorful.BORDER).exceptLeft().build();
/** 除了右边框 */
- Border EX_RIGHT = new BorderStroke(Colorful.BORDER).exRight().build();
+ Border EX_RIGHT = BorderBuilder.solid(Colorful.BORDER).exceptRight().build();
/** 除了下边框 */
- Border EX_BOTTOM = new BorderStroke(Colorful.BORDER).exBottom().build();
+ Border EX_BOTTOM = BorderBuilder.solid(Colorful.BORDER).exceptBottom().build();
/** 上右边框 */
- Border TR = new BorderStroke(Colorful.BORDER).width(1, 1, 0, 0).build();
+ Border TR = BorderBuilder.solid(Colorful.BORDER).width(1, 1, 0, 0).build();
/** 右下边框 */
- Border RB = new BorderStroke(Colorful.BORDER).width(0, 1, 1, 0).build();
+ Border RB = BorderBuilder.solid(Colorful.BORDER).width(0, 1, 1, 0).build();
/** 左下边框 */
- Border BL = new BorderStroke(Colorful.BORDER).width(0, 0, 1, 1).build();
+ Border BL = BorderBuilder.solid(Colorful.BORDER).width(0, 0, 1, 1).build();
/** 左上边框 */
- Border LT = new BorderStroke(Colorful.BORDER).width(1, 0, 0, 1).build();
+ Border LT = BorderBuilder.solid(Colorful.BORDER).width(1, 0, 0, 1).build();
/** 水平边框,边的方向而非位置 */
- Border H = new BorderStroke(Colorful.BORDER).width(1, 0).build();
+ Border H = BorderBuilder.solid(Colorful.BORDER).width(1, 0).build();
/** 垂直边框,边的方向而非位置 */
- Border V = new BorderStroke(Colorful.BORDER).width(0, 1).build();
+ Border V = BorderBuilder.solid(Colorful.BORDER).width(0, 1).build();
}
/**
@@ -279,37 +327,37 @@ public interface TimiFXUI {
interface BG {
/** FX 默认背景(#F4F4F4) */
- Background DEFAULT = new BgFill(Colorful.GRAY_WHITE).build();
+ Background DEFAULT = BackgroundFillBuilder.solid(Colorful.GRAY_WHITE).build();
/** 灰色背景 */
- Background GRAY = new BgFill(Colorful.GRAY).build();
+ Background GRAY = BackgroundFillBuilder.solid(Colorful.GRAY).build();
/** 亮灰背景 */
- Background LIGHT_GRAY = new BgFill(Colorful.LIGHT_GRAY).build();
+ Background LIGHT_GRAY = BackgroundFillBuilder.solid(Colorful.LIGHT_GRAY).build();
/** 纯黑背景 */
- Background BLACK = new BgFill(Colorful.BLACK).build();
+ Background BLACK = BackgroundFillBuilder.solid(Colorful.BLACK).build();
/** 纯白背景 */
- Background WHITE = new BgFill(Colorful.WHITE).build();
+ Background WHITE = BackgroundFillBuilder.solid(Colorful.WHITE).build();
/** 透明背景 */
- Background TRANSPARENT = new BgFill(Colorful.TRANSPARENT).build();
+ Background TRANSPARENT = BackgroundFillBuilder.solid(Colorful.TRANSPARENT).build();
/** 淡蓝背景 */
- Background LIGHT_BLUE = new BgFill(Colorful.LIGHT_BLUE).build();
+ Background LIGHT_BLUE = BackgroundFillBuilder.solid(Colorful.LIGHT_BLUE).build();
/** 聚焦色背景 */
- Background FOCUSED = new BgFill(Colorful.FOCUSED_DEFAULT).build();
+ Background FOCUSED = BackgroundFillBuilder.solid(Colorful.FOCUSED_DEFAULT).build();
/** 指向背景,通常用于提示组件尺寸响应拖动 */
- Background HOVER = new BgFill("#0007").build();
+ Background HOVER = BackgroundFillBuilder.solid("#0007").build();
/** 渐变的标题背景 */
- Background TITLE = new BgFill("#DDD", "#F4F4F400").toRight().build();
+ Background TITLE = BackgroundFillBuilder.linear("#DDD", "#F4F4F400").toRight().build();
/** 填充的标题背景 */
- Background TITLE_FILL = new BgFill("#DDD").build();
+ Background TITLE_FILL = BackgroundFillBuilder.solid("#DDD").build();
}
/**
@@ -378,6 +426,12 @@ public interface TimiFXUI {
return label;
}
+ static Label gridLabel(String text) {
+ Label label = Layout.margin.top(GridPane::setMargin, TimiFXUI.label(text), 4);
+ GridPane.setValignment(label, VPos.TOP);
+ return label;
+ }
+
/**
* 构建通用标题标签
*
diff --git a/src/main/java/com/imyeyu/fx/ui/components/DateTimePicker.java b/src/main/java/com/imyeyu/fx/ui/components/DateTimePicker.java
index 21d80c6..58e3d83 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/DateTimePicker.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/DateTimePicker.java
@@ -2,7 +2,9 @@ package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
+import com.imyeyu.fx.utils.Nodes;
import com.imyeyu.java.bean.Callback;
import com.imyeyu.utils.Time;
import com.sun.javafx.scene.control.DatePickerContent;
@@ -62,16 +64,16 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
minute = new ListView<>();
second = new ListView<>();
- hour.getStyleClass().add(CSS.BORDER_RB);
- minute.getStyleClass().add(CSS.BORDER_RB);
- second.getStyleClass().add(CSS.BORDER_B);
+ hour.setBorder(Stroke.RB);
+ minute.setBorder(Stroke.RB);
+ second.setBorder(Stroke.BOTTOM);
GridPane hmsPane = new GridPane();
hmsPane.getStyleClass().add(STYLE_CLASS_TIME_BOX);
hmsPane.addRow(0, hour, minute, second);
Button now = new Button(TimiFXUI.MULTILINGUAL.text("now_tick"));
- now.getStyleClass().add(CSS.BORDER_L);
+ now.setBorder(Stroke.LEFT);
now.getStyleClass().add(STYLE_CLASS_NOW);
timePane = new BorderPane(hmsPane);
@@ -111,8 +113,8 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
// 失焦关闭而非选择后关闭
}
};
- IconButton clear = new IconButton(TimiFXIcon.fromName("FAIL", GRAY));
- clear.getStyleClass().add(CSS.BORDER_ALL);
+ IconButton clear = new IconButton(TimiFXIcon.get(TimiIcon.FAIL, GRAY));
+ clear.setBorder(Stroke.DEFAULT);
clear.getStyleClass().add(STYLE_CLASS_CLEAR);
clear.translateXProperty().bind(widthProperty().subtract(40));
clear.setTranslateY(15);
@@ -186,9 +188,9 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
- TimiFX.hoverFocus(hour);
- TimiFX.hoverFocus(minute);
- TimiFX.hoverFocus(second);
+ Nodes.requestFocusOnHover(hour);
+ Nodes.requestFocusOnHover(minute);
+ Nodes.requestFocusOnHover(second);
// 此刻
now.setOnAction(e -> setValue(Time.now()));
diff --git a/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java b/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java
index 7831412..b272928 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/FileTreeView.java
@@ -1,13 +1,14 @@
package com.imyeyu.fx.ui.components;
-import com.imyeyu.fx.ObservableUtils;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.task.RunAsync;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.components.alert.AlertButton;
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
import com.imyeyu.fx.ui.components.alert.AlertTextField;
import com.imyeyu.fx.ui.components.alert.AlertTips;
+import com.imyeyu.fx.utils.Observables;
import com.imyeyu.io.IO;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.CallbackArgReturn;
@@ -64,8 +65,8 @@ public class FileTreeView extends TreeView implements TimiFXUI.Colorful {
setCellFactory(cell -> new TreeCell<>() {
final Label loading = new Label(TimiFXUI.MULTILINGUAL.text("loading"));
- final Text iconFile = TimiFXIcon.fromName("FILE");
- final Text iconDirectory = TimiFXIcon.fromName("FOLDER");
+ final Text iconFile = TimiFXIcon.get(TimiIcon.FILE);
+ final Text iconDirectory = TimiFXIcon.get(TimiIcon.FOLDER);
{
iconFile.fillProperty().bind(Bindings.when(FileTreeView.this.focusedProperty().and(selectedProperty())).then(GRAY_WHITE).otherwise(GRAY));
@@ -94,10 +95,10 @@ public class FileTreeView extends TreeView implements TimiFXUI.Colorful {
});
// 右键菜单
- MenuItem menuMkdir = new MenuItem(TimiFXUI.MULTILINGUAL.text("file.mkdir"), TimiFXIcon.fromName("FOLDER_ADD"));
+ MenuItem menuMkdir = new MenuItem(TimiFXUI.MULTILINGUAL.text("file.mkdir"), TimiFXIcon.get(TimiIcon.FOLDER_ADD));
MenuItem menuRename = new MenuItem(TimiFXUI.MULTILINGUAL.text("rename"));
- MenuItem menuRefresh = new MenuItem(TimiFXUI.MULTILINGUAL.text("refresh"), TimiFXIcon.fromName("REFRESH"));
- MenuItem menuDestroy = new MenuItem(TimiFXUI.MULTILINGUAL.text("delete"), TimiFXIcon.fromName("FAIL", RED));
+ MenuItem menuRefresh = new MenuItem(TimiFXUI.MULTILINGUAL.text("refresh"), TimiFXIcon.get(TimiIcon.REFRESH));
+ MenuItem menuDestroy = new MenuItem(TimiFXUI.MULTILINGUAL.text("delete"), TimiFXIcon.get(TimiIcon.FAIL, RED));
setContextMenu(new ContextMenu(menuMkdir, menuRename, menuRefresh, TimiFXUI.sep(), menuDestroy));
@@ -108,7 +109,7 @@ public class FileTreeView extends TreeView implements TimiFXUI.Colorful {
menuMkdir.setOnAction(e -> mkdir(getSelectionModel().getSelectedItem()));
// 重命名
- menuRename.disableProperty().bind(ObservableUtils.onlyOnceInList(getSelectionModel().getSelectedItems()).not());
+ menuRename.disableProperty().bind(Observables.onlyOnceInList(getSelectionModel().getSelectedItems()).not());
menuRename.setOnAction(e -> rename(getSelectionModel().getSelectedItem()));
// 刷新
diff --git a/src/main/java/com/imyeyu/fx/ui/components/IconButton.java b/src/main/java/com/imyeyu/fx/ui/components/IconButton.java
index 2780f31..b6318cf 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/IconButton.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/IconButton.java
@@ -1,8 +1,8 @@
package com.imyeyu.fx.ui.components;
-import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.java.TimiJava;
+import com.imyeyu.fx.utils.Nodes;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
@@ -13,6 +13,7 @@ import javafx.scene.control.Button;
import javafx.scene.control.Skin;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
+import javafx.scene.layout.Border;
import javafx.scene.paint.Paint;
/**
@@ -118,7 +119,7 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
if (node != null) {
setGraphic(node);
}
- TimiFX.hoverOpacity(this);
+ Nodes.bindHoverOpacity(this);
// 自适应尺寸、单独图标、图标文本混合时设置不同的内边距
paddingProperty().bind(Bindings.createObjectBinding(() -> {
@@ -140,7 +141,22 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
* @return 本实例
*/
public IconButton withBackground() {
- return withBackground(null);
+ return withBackground((Border) null);
+ }
+
+ /**
+ * 添加按钮背景
+ *
+ * @param border 边框
+ * @return 本实例
+ */
+ public IconButton withBackground(Border border) {
+ getStyleClass().add(CSS.BG_BUTTON);
+ if (border != null) {
+ setBorder(border);
+ }
+ opacityProperty().unbind();
+ return this;
}
/**
@@ -150,11 +166,13 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
* @return 本实例
*/
public IconButton withBackground(String borderClass) {
- getStyleClass().add(CSS.BG_BUTTON);
+ return withBackground().appendBorderStyle(borderClass);
+ }
+
+ private IconButton appendBorderStyle(String borderClass) {
if (TimiJava.isNotEmpty(borderClass)) {
getStyleClass().add(borderClass);
}
- opacityProperty().unbind();
return this;
}
diff --git a/src/main/java/com/imyeyu/fx/ui/components/IconPicker.java b/src/main/java/com/imyeyu/fx/ui/components/IconPicker.java
index 2db9f2d..f8b8ed6 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/IconPicker.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/IconPicker.java
@@ -1,9 +1,10 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
-import com.imyeyu.fx.utils.BgFill;
-import com.imyeyu.fx.utils.SmoothScroll;
+import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
+import com.imyeyu.fx.utils.scroll.SmoothScroll;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.ref.Ref;
import com.imyeyu.utils.Collect;
@@ -29,8 +30,12 @@ import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* {@link TimiFXIcon} 的图标选择器(标签搜索需要联网)
@@ -58,7 +63,7 @@ public class IconPicker extends TextField implements TimiFXUI {
if (TimiJava.isEmpty(value)) {
root.setLeft(null);
} else {
- Text icon = TimiFXIcon.fromName(value);
+ Text icon = TimiFXIcon.get(TimiIcon.valueOf(value));
BorderPane.setMargin(icon, new Insets(0, 2, 0, 0));
BorderPane.setAlignment(icon, Pos.CENTER);
root.setLeft(icon);
@@ -81,7 +86,7 @@ public class IconPicker extends TextField implements TimiFXUI {
if (newToggle == null) {
clear();
} else if (newToggle instanceof ToggleIcon icon) {
- setText(icon.name.toUpperCase());
+ setText(icon.value.toString());
}
});
}
@@ -109,7 +114,7 @@ public class IconPicker extends TextField implements TimiFXUI {
* @return 图标图像
*/
public Image getValue() {
- return TimiFXIcon.imageFromName(getText());
+ return TimiFXIcon.getImage(TimiIcon.valueOf(getText()));
}
/**
@@ -122,7 +127,7 @@ public class IconPicker extends TextField implements TimiFXUI {
final ToggleGroup group;
final List icons;
- final Map nameMapping = TimiFXIcon.getNameMapping();
+ final Map unicodeMap = Arrays.stream(TimiIcon.values()).collect(Collectors.toMap(Function.identity(), TimiIcon::getUnicode));
public IconPickerPopup() {
// 图标
@@ -131,13 +136,12 @@ public class IconPicker extends TextField implements TimiFXUI {
icons = new ArrayList<>();
group = new ToggleGroup();
- Map items = Collect.sortMapByStringKeyASC(nameMapping);
- for (Map.Entry item : items.entrySet()) {
+ Map items = Collect.sortMap(unicodeMap, Comparator.comparing(Enum::name));
+ for (Map.Entry item : items.entrySet()) {
icons.add(new ToggleIcon(group, item.getKey()));
}
tile.getChildren().addAll(icons);
-
- focusedProperty().addListener((obs, o, isFocused) -> {
+ focusedProperty().addListener((_, _, isFocused) -> {
if (!isFocused) {
hide();
}
@@ -156,12 +160,12 @@ public class IconPicker extends TextField implements TimiFXUI {
setPadding(new Insets(6, 8, 6, 8));
setFitToWidth(true);
- SmoothScroll.scrollPane(this);
+ SmoothScroll.pane.install(this);
}});
}});
}});
scene.setFill(null);
- scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
+ TimiFXUI.applyStyle(scene);
setScene(scene);
setWidth(360);
setHeight(240);
@@ -177,16 +181,16 @@ public class IconPicker extends TextField implements TimiFXUI {
*/
private static class ToggleIcon extends ToggleButton {
- private static final Background SELECTED = new BgFill("#99D1FF").build();
+ private static final Background SELECTED = BackgroundFillBuilder.solid("#99D1FF").build();
/** 图标名称 */
- final String name;
+ final TimiIcon value;
- public ToggleIcon(ToggleGroup ownerGroup, String name) {
+ public ToggleIcon(ToggleGroup ownerGroup, TimiIcon value) {
super("");
- this.name = name;
+ this.value = value;
- setGraphic(TimiFXIcon.fromName(name));
+ setGraphic(TimiFXIcon.get(value, 16));
getStyleClass().clear();
managedProperty().bind(visibleProperty());
borderProperty().bind(Bindings.when(hoverProperty()).then(Stroke.FOCUSED).otherwise(Stroke.TP));
diff --git a/src/main/java/com/imyeyu/fx/ui/components/Pagination.java b/src/main/java/com/imyeyu/fx/ui/components/Pagination.java
index f14417e..dbc3f38 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/Pagination.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/Pagination.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
@@ -15,6 +16,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Border;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
@@ -79,8 +81,7 @@ public class Pagination extends HBox implements TimiFXUI {
PageButton tb;
// 上一页
- prev = new IconButton(TimiFXIcon.fromName("ARROW_1_W")).withBackground();
- prev.getStyleClass().add(CSS.BORDER_N);
+ prev = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_1_W)).withBackground(Border.EMPTY);
prev.setMaxHeight(Double.MAX_VALUE);
prev.disableProperty().bind(ip.isEqualTo(0));
getChildren().add(prev);
@@ -96,7 +97,7 @@ public class Pagination extends HBox implements TimiFXUI {
// 2. 总页数大于等于 8,激活下标小于 4(1 - 4 页)
tb.visibleProperty().bind(cp.greaterThan(i).and(cp.lessThan(8)).or(cp.greaterThan(7).and(ip.lessThan(4))));
} else {
- tb.getStyleClass().add(CSS.BORDER_LR);
+ tb.setBorder(Stroke.V);
}
pageButtons.add(tb);
getChildren().add(tb);
@@ -149,9 +150,8 @@ public class Pagination extends HBox implements TimiFXUI {
}
// 下一页
- next = new IconButton(TimiFXIcon.fromName("ARROW_1_E")).withBackground();
+ next = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_1_E)).withBackground(Border.EMPTY);
next.setMaxHeight(Double.MAX_VALUE);
- next.getStyleClass().add(CSS.BORDER_N);
next.disableProperty().bind(ip.isEqualTo(cp.subtract(1)).or(cp.isEqualTo(0)));
getStyleClass().add(STYLE_CLASS);
@@ -324,7 +324,8 @@ public class Pagination extends HBox implements TimiFXUI {
public PageButton() {
indexProperty = new SimpleIntegerProperty();
- getStyleClass().addAll(CSS.BORDER_R, CSS.BG_BUTTON);
+ getStyleClass().add(CSS.BG_BUTTON);
+ setBorder(Stroke.RIGHT);
// 页码即显示内容
textProperty().bind(indexProperty.add(1).asString());
managedProperty().bind(visibleProperty());
diff --git a/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroup.java b/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroup.java
index 7e9a0fa..45e2bb4 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroup.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroup.java
@@ -1,6 +1,6 @@
package com.imyeyu.fx.ui.components;
-import com.imyeyu.fx.TimiFX;
+import com.imyeyu.fx.utils.Nodes;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
@@ -14,12 +14,16 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
+import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
+import lombok.Getter;
/**
* 单选按钮组组件
@@ -75,6 +79,7 @@ public class RadioButtonGroup extends Control {
public static final String STYLE_CLASS_SINGLE = "single";
/** 按钮列表 */
+ @Getter
private final ObservableList buttons;
/** 按钮组 */
@@ -99,8 +104,15 @@ public class RadioButtonGroup extends Control {
private final BooleanProperty allowClearSelection;
/** 禁止重复点击清空 */
- private final javafx.event.EventHandler keepSelectionEvent = event -> {
- if (!isAllowClearSelection() && event.getSource() instanceof ToggleButton button && button.isSelected()) {
+ private final EventHandler keepSelectionEvent = event -> {
+ if (shouldKeepSelection(event.getSource())) {
+ event.consume();
+ }
+ };
+
+ /** 禁止通过键盘重复触发清空 */
+ private final EventHandler keepSelectionKeyEvent = event -> {
+ if ((event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) && shouldKeepSelection(event.getSource())) {
event.consume();
}
};
@@ -130,7 +142,11 @@ public class RadioButtonGroup extends Control {
* 初始化选中同步
*/
private void initSelectionSync() {
- toggleGroup.selectedToggleProperty().addListener((obs, o, toggle) -> {
+ toggleGroup.selectedToggleProperty().addListener((obs, oldToggle, toggle) -> {
+ if (!isAllowClearSelection() && toggle == null && oldToggle instanceof ToggleButton button && buttons.contains(button)) {
+ toggleGroup.selectToggle(button);
+ return;
+ }
if (toggle instanceof ToggleButton button) {
selectedButton.set(button);
selectedIndex.set(buttons.indexOf(button));
@@ -178,7 +194,7 @@ public class RadioButtonGroup extends Control {
* 初始化模式样式
*/
private void initModeStyleClass() {
- TimiFX.toggleStyleClass4Binding(this, mode.isEqualTo(Mode.SLIDER), STYLE_CLASS_SLIDER_MODE, STYLE_CLASS_BUTTON_MODE);
+ Nodes.bindStyleClass(this, mode.isEqualTo(Mode.SLIDER), STYLE_CLASS_SLIDER_MODE, STYLE_CLASS_BUTTON_MODE);
}
/**
@@ -192,6 +208,8 @@ public class RadioButtonGroup extends Control {
}
button.setToggleGroup(toggleGroup);
button.addEventFilter(MouseEvent.MOUSE_PRESSED, keepSelectionEvent);
+ button.addEventFilter(KeyEvent.KEY_PRESSED, keepSelectionKeyEvent);
+ button.addEventFilter(KeyEvent.KEY_RELEASED, keepSelectionKeyEvent);
}
/**
@@ -201,11 +219,23 @@ public class RadioButtonGroup extends Control {
*/
private void detachButton(ToggleButton button) {
button.removeEventFilter(MouseEvent.MOUSE_PRESSED, keepSelectionEvent);
+ button.removeEventFilter(KeyEvent.KEY_PRESSED, keepSelectionKeyEvent);
+ button.removeEventFilter(KeyEvent.KEY_RELEASED, keepSelectionKeyEvent);
if (button.getToggleGroup() == toggleGroup) {
button.setToggleGroup(null);
}
}
+ /**
+ * 判断是否需要保持当前选中
+ *
+ * @param source 事件源
+ * @return true 为拦截当前重复触发
+ */
+ private boolean shouldKeepSelection(Object source) {
+ return !isAllowClearSelection() && source instanceof ToggleButton button && button.isSelected();
+ }
+
/**
* 同步当前选中状态
*/
@@ -235,15 +265,6 @@ public class RadioButtonGroup extends Control {
return new RadioButtonGroupSkin(this);
}
- /**
- * 获取按钮列表
- *
- * @return 按钮列表
- */
- public ObservableList getButtons() {
- return buttons;
- }
-
/**
* 添加按钮
*
diff --git a/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroupSkin.java b/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroupSkin.java
index 69d460b..131e814 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroupSkin.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroupSkin.java
@@ -1,11 +1,9 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.bean.Interpolates;
-
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
-import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
@@ -14,7 +12,6 @@ import javafx.geometry.Bounds;
import javafx.scene.control.SkinBase;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.HBox;
-import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
@@ -27,11 +24,8 @@ import javafx.util.Duration;
*/
public class RadioButtonGroupSkin extends SkinBase {
- /** 高度补偿 */
- private static final double HEIGHT_COMPENSATE = 2;
-
/** 动画时长 */
- private static final Duration SLIDER_DURATION = Duration.millis(180);
+ private static final Duration SLIDER_DURATION = Duration.millis(320);
/** 按钮容器 */
private final HBox box;
@@ -159,25 +153,6 @@ public class RadioButtonGroupSkin extends SkinBase {
}
}
- /**
- * 刷新按钮尺寸策略
- */
- private void refreshButtonSizing() {
- boolean sliderMode = getSkinnable().getMode() == RadioButtonGroup.Mode.SLIDER;
- for (ToggleButton button : getSkinnable().getButtons()) {
- button.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
- button.setPrefHeight(Region.USE_COMPUTED_SIZE);
- if (sliderMode) {
- HBox.setHgrow(button, Priority.NEVER);
- button.setMaxWidth(Region.USE_PREF_SIZE);
- }
- else {
- HBox.setHgrow(button, Priority.ALWAYS);
- button.setMaxWidth(Double.MAX_VALUE);
- }
- }
- }
-
/**
* 应用滑块位置和尺寸
*/
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TabPane.java b/src/main/java/com/imyeyu/fx/ui/components/TabPane.java
index 8cbb41b..9311e34 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TabPane.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TabPane.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.java.bean.CallbackArg;
import com.imyeyu.java.ref.Ref;
@@ -48,7 +49,7 @@ public class TabPane extends javafx.scene.control.TabPane implements TimiFXUI, T
closeBtn.setPrefWidth(18);
closeBtn.getStyleClass().clear();
- IconButton icon = new IconButton(TimiFXIcon.fromName("FAIL", GRAY));
+ IconButton icon = new IconButton(TimiFXIcon.get(TimiIcon.FAIL, GRAY));
icon.setAlignment(Pos.CENTER_LEFT);
icon.setMouseTransparent(true);
icon.prefWidthProperty().bind(closeBtn.widthProperty());
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditor.java b/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditor.java
index 78e33f1..4cb0865 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditor.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditor.java
@@ -1,11 +1,12 @@
package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.components.popup.PopupTipsService;
-import com.imyeyu.fx.utils.Anchor;
-import com.imyeyu.fx.utils.Column;
-import com.imyeyu.fx.utils.SmoothScroll;
+import com.imyeyu.fx.utils.grid.Column;
+import com.imyeyu.fx.utils.layout.Layout;
+import com.imyeyu.fx.utils.scroll.SmoothScroll;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.Callback;
import com.imyeyu.java.ref.Ref;
@@ -38,6 +39,7 @@ import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Border;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
@@ -116,31 +118,31 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
showLineNumber = new SimpleBooleanProperty(true);
// 撤销
- undo = new IconButton(TimiFXIcon.fromName("ARROW_0_W")).withBackground(CSS.BORDER_R);
+ undo = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_W)).withBackground(Stroke.RIGHT);
undo.disableProperty().bind(undoableProperty().not());
PopupTipsService.installText(undo, TimiFXUI.MULTILINGUAL.text("undo"));
// 重做
- redo = new IconButton(TimiFXIcon.fromName("ARROW_0_E")).withBackground(CSS.BORDER_R);
+ redo = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_E)).withBackground(Stroke.RIGHT);
redo.disableProperty().bind(redoableProperty().not());
PopupTipsService.installText(redo, TimiFXUI.MULTILINGUAL.text("redo"));
// 复制
- copy = new IconButton(TimiFXIcon.fromName("COPY")).withBackground(CSS.BORDER_R);
+ copy = new IconButton(TimiFXIcon.get(TimiIcon.COPY)).withBackground(Stroke.RIGHT);
PopupTipsService.installText(copy, TimiFXUI.MULTILINGUAL.text("copy"));
// 剪切
- cut = new IconButton(TimiFXIcon.fromName("CUT")).withBackground(CSS.BORDER_R);
+ cut = new IconButton(TimiFXIcon.get(TimiIcon.CUT)).withBackground(Stroke.RIGHT);
cut.disableProperty().bind(editableProperty().not());
PopupTipsService.installText(cut, TimiFXUI.MULTILINGUAL.text("cut"));
// 粘贴
- paste = new IconButton(TimiFXIcon.fromName("PASTE")).withBackground(CSS.BORDER_R);
+ paste = new IconButton(TimiFXIcon.get(TimiIcon.PASTE)).withBackground(Stroke.RIGHT);
paste.disableProperty().bind(editableProperty().not());
PopupTipsService.installText(paste, TimiFXUI.MULTILINGUAL.text("paste"));
// 换行
- wrap = new ToggleIcon(TimiFXIcon.fromName("WRAP"));
+ wrap = new ToggleIcon(TimiFXIcon.get(TimiIcon.WRAP));
wrap.setBorder(Stroke.RIGHT);
PopupTipsService.installText(wrap, TimiFXUI.MULTILINGUAL.text("wrap"));
@@ -154,12 +156,13 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
// 顶部背景(阻止触发文本域选择)
Button headerBackground = new Button(" ");
- headerBackground.getStyleClass().addAll(CSS.BORDER_N, CSS.BG_TP);
+ headerBackground.getStyleClass().add(CSS.BG_TP);
+ headerBackground.setBorder(Border.EMPTY);
headerBackground.setBackground(BG.DEFAULT);
AnchorPane headerPane = new AnchorPane();
- Anchor.def(header);
- Anchor.def(headerBackground);
+ Layout.anchor.fill(header);
+ Layout.anchor.fill(headerBackground);
headerPane.getChildren().setAll(headerBackground, header);
headerPane.setBorder(Stroke.BOTTOM);
@@ -321,7 +324,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
});
// 平滑滚动
- SmoothScroll.scrollPaneV(scrollPane);
+ SmoothScroll.pane.install(scrollPane);
root.setLeft(lineNumber);
root.setCenter(scrollPane);
@@ -412,7 +415,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
selects = FXCollections.observableHashMap();
// 查找
- Text icon = TimiFXIcon.fromName("MAGNIFIER");
+ Text icon = TimiFXIcon.get(TimiIcon.MAGNIFIER);
keyword = new TextField() {
@Override
@@ -426,7 +429,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
textGroup.setTranslateY(-.5);
// 匹配大小写
- toggleCase = new ToggleIcon(TimiFXIcon.fromName("FONTSIZE"));
+ toggleCase = new ToggleIcon(TimiFXIcon.get(TimiIcon.FONT_SIZE));
toggleCase.setBorder(Stroke.LEFT);
toggleCase.setCursor(Cursor.DEFAULT);
toggleCase.setFocusTraversable(false);
@@ -446,29 +449,31 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
}
};
keyword.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
- keyword.getStyleClass().addAll("find-field", CSS.BORDER_R, CSS.PADDING_N);
+ keyword.getStyleClass().addAll("find-field", CSS.PADDING_N);
+ keyword.setBorder(Stroke.RIGHT);
// 查找结果
result = TimiFXUI.label(" ");
result.setPadding(new Insets(0, 4, 0, 4));
- IconButton prev = new IconButton(TimiFXIcon.fromName("ARROW_0_N")).withBackground();
- prev.getStyleClass().add(CSS.BORDER_R);
+ IconButton prev = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_N)).withBackground();
+ prev.setBorder(Stroke.RIGHT);
prev.setFocusTraversable(false);
- IconButton next = new IconButton(TimiFXIcon.fromName("ARROW_0_S")).withBackground();
- next.getStyleClass().add(CSS.BORDER_R);
+ IconButton next = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_S)).withBackground();
+ next.setBorder(Stroke.RIGHT);
next.setFocusTraversable(false);
// 关闭
- IconButton close = new IconButton(TimiFXIcon.fromName("FAIL")).withBackground();
- close.getStyleClass().add(CSS.BORDER_L);
+ IconButton close = new IconButton(TimiFXIcon.get(TimiIcon.FAIL)).withBackground();
+ close.setBorder(Stroke.LEFT);
close.setFocusTraversable(false);
// 替换值
TextField replaceValue = new TextField();
- replaceValue.getStyleClass().addAll("replace-field", CSS.BORDER_TR);
+ replaceValue.getStyleClass().add("replace-field");
+ replaceValue.setBorder(Stroke.TR);
replaceValue.disableProperty().bind(editableProperty().not());
Button replace = new Button(TimiFXUI.MULTILINGUAL.text("replace"));
- replace.getStyleClass().add(CSS.BORDER_R);
+ replace.setBorder(Stroke.RIGHT);
replace.setFocusTraversable(false);
replace.disableProperty().bind(editableProperty().not().or(replaceValue.textProperty().isEmpty().or(Bindings.isEmpty(selects))));
replace.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
@@ -477,12 +482,12 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
}
});
Button replaceAll = new Button(TimiFXUI.MULTILINGUAL.text("replace_all"));
- replaceAll.getStyleClass().add(CSS.BORDER_R);
+ replaceAll.setBorder(Stroke.RIGHT);
replaceAll.setFocusTraversable(false);
replaceAll.disableProperty().bind(replace.disabledProperty());
getStyleClass().add("find-pane");
- getColumnConstraints().addAll(Column.build(), Column.build().width(260), Column.VALUE_FILL);
+ getColumnConstraints().addAll(Column.builder().build(), Column.builder().width(260).build(), Column.valueFill());
setBorder(Stroke.BOTTOM);
setBackground(BG.DEFAULT);
@@ -645,7 +650,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
// 不可单向绑定,TextArea 内部需要调度 setVvalue,也不可双向绑定,会造成滚动错位
scrollPane.setVvalue(newV.doubleValue());
});
- getStyleClass().add(CSS.BORDER_L);
+ setBorder(Stroke.LEFT);
setEditable(false);
setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
addEventFilter(MouseEvent.ANY, Event::consume);
@@ -688,7 +693,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
scrollPane.vvalueProperty().addListener((obs, o, n) -> scrollPane.setVvalue(ownerScrollPane.getVvalue()));
scrollPane.getContent().setCursor(Cursor.DEFAULT);
- SmoothScroll.scrollPaneV(scrollPane);
+ SmoothScroll.pane.install(scrollPane);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditorField.java b/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditorField.java
index f0c8930..e5e3247 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditorField.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TextAreaEditorField.java
@@ -2,7 +2,9 @@ package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
+import com.imyeyu.fx.utils.Windows;
import com.imyeyu.java.bean.CallbackArg;
import com.imyeyu.java.ref.Ref;
import javafx.beans.property.SimpleStringProperty;
@@ -71,8 +73,7 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
textGroup.setTranslateY(-.5);
// 插入编辑器图标
- IconButton editor = new IconButton(TimiFXIcon.fromName("WRITING")).withBackground();
- editor.getStyleClass().add(CSS.BORDER_L);
+ IconButton editor = new IconButton(TimiFXIcon.get(TimiIcon.WRITING)).withBackground(Stroke.LEFT);
editor.setCursor(Cursor.DEFAULT);
BorderPane root = new BorderPane();
@@ -88,7 +89,7 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
if (onShowEditorEvent != null) {
onShowEditorEvent.handler(editorStage);
}
- TimiFX.showCenter(getScene().getWindow(), editorStage);
+ Windows.showCentered(getScene().getWindow(), editorStage);
});
} catch (IllegalAccessException e) {
@@ -138,12 +139,12 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
EditorStage() {
editor = new TextAreaEditor();
- editor.getStyleClass().add(CSS.BORDER_T);
+ editor.setBorder(Stroke.TOP);
Scene scene = new Scene(editor);
- scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
+ TimiFXUI.applyStyle(scene);
setScene(scene);
- getIcons().add(TimiFXIcon.iconFromName("WRITING"));
+ getIcons().add(TimiFXIcon.rerender(TimiIcon.WRITING));
setWidth(850);
setHeight(620);
}
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TimePicker.java b/src/main/java/com/imyeyu/fx/ui/components/TimePicker.java
index a718394..e1aace1 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TimePicker.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TimePicker.java
@@ -2,7 +2,9 @@ package com.imyeyu.fx.ui.components;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
+import com.imyeyu.fx.utils.Nodes;
import com.imyeyu.utils.Time;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
@@ -51,21 +53,20 @@ public class TimePicker extends HBox implements TimiFXUI {
textField.setAlignment(Pos.CENTER);
textField.setPrefWidth(70);
textField.setOnContextMenuRequested(Event::consume);
- IconButton button = new IconButton(TimiFXIcon.fromName("CLOCK")).withBackground();
- button.getStyleClass().add(CSS.BORDER_TRB);
+ IconButton button = new IconButton(TimiFXIcon.get(TimiIcon.CLOCK)).withBackground(Stroke.EX_LEFT);
// 时间选择
hour = new ListView<>();
minute = new ListView<>();
second = new ListView<>();
- hour.getStyleClass().add(CSS.BORDER_RB);
- minute.getStyleClass().add(CSS.BORDER_RB);
- second.getStyleClass().add(CSS.BORDER_B);
+ hour.setBorder(Stroke.RB);
+ minute.setBorder(Stroke.RB);
+ second.setBorder(Stroke.BOTTOM);
// 此刻
Button now = new Button(TimiFXUI.MULTILINGUAL.text("now"));
- now.getStyleClass().add(CSS.BORDER_L);
+ now.setBorder(Stroke.LEFT);
now.getStyleClass().add(STYLE_CLASS_NOW);
HBox timeBox = new HBox(hour, minute, second);
@@ -134,9 +135,9 @@ public class TimePicker extends HBox implements TimiFXUI {
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
- TimiFX.hoverFocus(hour);
- TimiFX.hoverFocus(minute);
- TimiFX.hoverFocus(second);
+ Nodes.requestFocusOnHover(hour);
+ Nodes.requestFocusOnHover(minute);
+ Nodes.requestFocusOnHover(second);
// 值监听
value.addListener((obs, o, n) -> {
diff --git a/src/main/java/com/imyeyu/fx/ui/components/ToggleIcon.java b/src/main/java/com/imyeyu/fx/ui/components/ToggleIcon.java
index d5094ef..f6932df 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/ToggleIcon.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/ToggleIcon.java
@@ -1,8 +1,8 @@
package com.imyeyu.fx.ui.components;
-import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.ui.TimiFXUI;
-import com.imyeyu.fx.utils.BgFill;
+import com.imyeyu.fx.utils.Nodes;
+import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
import com.imyeyu.java.TimiJava;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
@@ -25,7 +25,7 @@ import javafx.scene.layout.Background;
public class ToggleIcon extends ToggleButton implements TimiFXUI {
private static final String STYLE_CLASS = "toggle-icon";
- private static final Background BG_SELECTED = new BgFill("#99D1FF").build();
+ private static final Background BG_SELECTED = BackgroundFillBuilder.solid("#99D1FF").build();
/** 选中图标 */
protected final Node selected;
@@ -118,7 +118,7 @@ public class ToggleIcon extends ToggleButton implements TimiFXUI {
graphicProperty().bind(Bindings.when(selectedProperty()).then(selected).otherwise(otherwise));
}
selected.getStyleClass().add("icon");
- TimiFX.hoverOpacity(this);
+ Nodes.bindHoverOpacity(this);
getStyleClass().setAll(CSS.MINECRAFT, STYLE_CLASS);
setAlignment(Pos.CENTER);
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TrayFX.java b/src/main/java/com/imyeyu/fx/ui/components/TrayFX.java
index a2b56fa..0f944ec 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TrayFX.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TrayFX.java
@@ -106,7 +106,7 @@ public final class TrayFX implements TimiFXUI {
root = new StackPane();
Scene scene = new Scene(root);
- scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT, RESOURCE + "style/components/tray-menu.css");
+ TimiFXUI.applyStyle(scene, TrayFX.class.getResource(RESOURCE + "style/components/tray-menu.css").toExternalForm());
scene.setFill(null);
stage = new Stage();
stage.setWidth(1);
diff --git a/src/main/java/com/imyeyu/fx/ui/components/TreeView.java b/src/main/java/com/imyeyu/fx/ui/components/TreeView.java
index dbb04c8..b21aac4 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/TreeView.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/TreeView.java
@@ -1,6 +1,6 @@
package com.imyeyu.fx.ui.components;
-import com.imyeyu.fx.utils.SmoothScroll;
+import com.imyeyu.fx.utils.scroll.SmoothScroll;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
@@ -20,7 +20,7 @@ public class TreeView extends javafx.scene.control.TreeView {
setRoot(dummyRoot);
setShowRoot(false);
// 平滑滚动
- SmoothScroll.virtual(this);
+ SmoothScroll.virtual.install(this);
}
/**
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlert.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlert.java
index c28ad1b..84b6838 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlert.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlert.java
@@ -1,8 +1,8 @@
package com.imyeyu.fx.ui.components.alert;
-import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.ui.TimiFXUI;
-import com.imyeyu.fx.utils.ScreenFX;
+import com.imyeyu.fx.utils.Windows;
+import com.imyeyu.fx.utils.screen.Screens;
import com.imyeyu.java.bean.CallbackArg;
import com.imyeyu.java.bean.CallbackArgReturn;
import javafx.beans.property.ObjectProperty;
@@ -102,7 +102,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
}});
Scene scene = new Scene(root);
- scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
+ TimiFXUI.applyStyle(scene);
initModality(Modality.WINDOW_MODAL);
setScene(scene);
@@ -184,7 +184,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
initOwner(owner);
}
setOnShown(e -> {
- TimiFX.relativeCenter(owner, this);
+ Windows.centerOnOwner(owner, this);
callShownListeners(e);
});
show();
@@ -200,7 +200,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
initOwner(owner);
}
setOnShown(e -> {
- TimiFX.relativeCenter(owner, this);
+ Windows.centerOnOwner(owner, this);
callShownListeners(e);
});
showAndWait();
@@ -208,7 +208,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
/** 相对于主屏幕中间显示 */
public void showRelativeCenter4PrimaryScreen() {
- showRelativeCenter4Screen(ScreenFX.primary);
+ showRelativeCenter4Screen(Screens.primary());
}
/**
@@ -219,7 +219,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
public void showRelativeCenter4Screen(Screen screen) {
initModality(Modality.APPLICATION_MODAL);
setOnShown(e -> {
- TimiFX.relativeCenter4Screen(screen, this);
+ Windows.centerOnScreen(this, screen);
callShownListeners(e);
});
show();
@@ -227,7 +227,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
/** 相对于主屏幕中间显示并等待 */
public void showAwaitRelativeCenter4PrimaryScreen() {
- showAwaitRelativeCenter4Screen(ScreenFX.primary);
+ showAwaitRelativeCenter4Screen(Screens.primary());
}
/**
@@ -238,7 +238,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
public void showAwaitRelativeCenter4Screen(Screen screen) {
initModality(Modality.APPLICATION_MODAL);
setOnShown(e -> {
- TimiFX.relativeCenter4Screen(screen, this);
+ Windows.centerOnScreen(this, screen);
callShownListeners(e);
});
showAndWait();
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlertFile.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlertFile.java
index f2b6356..bf57e2a 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlertFile.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AbstractAlertFile.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.fx.ui.components.FileTreeView;
import com.imyeyu.fx.ui.components.IconButton;
@@ -18,6 +19,7 @@ import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
@@ -66,27 +68,23 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
VBox header = new VBox();
// 主页
- IconButton home = new IconButton(TimiFXIcon.fromName("HOME")).withBackground();
- home.getStyleClass().add(CSS.BORDER_R);
+ IconButton home = new IconButton(TimiFXIcon.get(TimiIcon.HOME)).withBackground(Stroke.RIGHT);
PopupTipsService.installText(home, TimiFXUI.MULTILINGUAL.text("home"));
// 刷新
- IconButton refresh = new IconButton(TimiFXIcon.fromName("REFRESH")).withBackground();
- refresh.getStyleClass().add(CSS.BORDER_R);
+ IconButton refresh = new IconButton(TimiFXIcon.get(TimiIcon.REFRESH)).withBackground(Stroke.RIGHT);
PopupTipsService.installText(refresh, TimiFXUI.MULTILINGUAL.text("refresh"));
// 创建文件夹
- IconButton mkdir = new IconButton(TimiFXIcon.fromName("FOLDER_ADD")).withBackground();
- mkdir.getStyleClass().add(CSS.BORDER_R);
+ IconButton mkdir = new IconButton(TimiFXIcon.get(TimiIcon.FOLDER_ADD)).withBackground(Stroke.RIGHT);
PopupTipsService.installText(mkdir, TimiFXUI.MULTILINGUAL.text("file.mkdir"));
// 删除
- IconButton destroy = new IconButton(TimiFXIcon.fromName("FAIL", Colorful.RED)).withBackground();
- destroy.getStyleClass().add(CSS.BORDER_R);
+ IconButton destroy = new IconButton(TimiFXIcon.get(TimiIcon.FAIL, Colorful.RED)).withBackground(Stroke.RIGHT);
PopupTipsService.installText(destroy, TimiFXUI.MULTILINGUAL.text("delete"));
// 切换隐藏
- toggleHide = new ToggleIcon(TimiFXIcon.fromName("HIDE"));
+ toggleHide = new ToggleIcon(TimiFXIcon.get(TimiIcon.HIDE));
PopupTipsService.installText(toggleHide, TimiFXUI.MULTILINGUAL.text("file.show_hide"));
BorderPane ctrl = new BorderPane();
@@ -99,9 +97,8 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
// 绝对路径
absolutePath = new TextField();
- absolutePath.getStyleClass().add(CSS.BORDER_N);
- IconButton absolutePathGo = new IconButton(TimiFXIcon.fromName("ARROW_2_E")).withBackground();
- absolutePathGo.getStyleClass().add(CSS.BORDER_L);
+ absolutePath.setBorder(Border.EMPTY);
+ IconButton absolutePathGo = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_2_E)).withBackground(Stroke.LEFT);
{
if (mode == SelectionMode.SINGLE) {
PopupTipsLabel tips = PopupTipsService.installBindingText(absolutePath, absolutePath.textProperty());
@@ -128,10 +125,10 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
{
confirm = AlertButton.confirm();
- confirm.getStyleClass().add(CSS.BORDER_L);
+ confirm.setBorder(Stroke.LEFT);
cancel = AlertButton.cancel();
- cancel.getStyleClass().add(CSS.BORDER_L);
+ cancel.setBorder(Stroke.LEFT);
setRightButtons(confirm, cancel);
btnPane.setPadding(Insets.EMPTY);
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileBlendSelector.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileBlendSelector.java
index 2b06eb2..1caf82e 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileBlendSelector.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileBlendSelector.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import javafx.beans.binding.Bindings;
import javafx.scene.control.SelectionMode;
@@ -24,7 +25,7 @@ public class AlertFileBlendSelector extends AbstractAlertFile {
// 确认
confirm.disableProperty().bind(Bindings.isEmpty(tree.getSelectionModel().getSelectedItems()));
- getIcons().setAll(TimiFXIcon.iconFromName("FOLDER"));
+ getIcons().setAll(TimiFXIcon.rerender(TimiIcon.FOLDER));
setTitle(TimiFXUI.MULTILINGUAL.text("file.tips.select_directory"));
}
}
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFilePathSelector.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFilePathSelector.java
index 050e56d..13e4afe 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFilePathSelector.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFilePathSelector.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import javafx.beans.binding.Bindings;
import javafx.scene.control.SelectionMode;
@@ -30,7 +31,7 @@ public class AlertFilePathSelector extends AbstractAlertFile {
return item == null || item.getValue().isFile();
}, tree.getSelectionModel().selectedItemProperty()));
- getIcons().setAll(TimiFXIcon.iconFromName("FOLDER"));
+ getIcons().setAll(TimiFXIcon.rerender(TimiIcon.FOLDER));
setTitle(TimiFXUI.MULTILINGUAL.text("file.tips.select_directory"));
addItemFilter(File::isDirectory);
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileSelector.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileSelector.java
index 77a346d..abc6e52 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileSelector.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertFileSelector.java
@@ -1,6 +1,7 @@
package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.icon.TimiFXIcon;
+import com.imyeyu.fx.icon.TimiIcon;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.io.IO;
import com.imyeyu.java.TimiJava;
@@ -44,7 +45,7 @@ public class AlertFileSelector extends AbstractAlertFile {
return item == null || item.getValue().isDirectory();
}, tree.getSelectionModel().selectedItemProperty()));
- getIcons().setAll(TimiFXIcon.iconFromName("FILE"));
+ getIcons().setAll(TimiFXIcon.rerender(TimiIcon.FILE));
setTitle(TimiFXUI.MULTILINGUAL.text("file.select"));
addItemFilter(file -> {
diff --git a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertTextArea.java b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertTextArea.java
index 0932630..ca912b9 100644
--- a/src/main/java/com/imyeyu/fx/ui/components/alert/AlertTextArea.java
+++ b/src/main/java/com/imyeyu/fx/ui/components/alert/AlertTextArea.java
@@ -2,7 +2,8 @@ package com.imyeyu.fx.ui.components.alert;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.ui.TimiFXUI;
-import com.imyeyu.fx.utils.SmoothScroll;
+import com.imyeyu.fx.utils.scroll.SmoothScroll;
+import com.imyeyu.fx.utils.Windows;
import com.imyeyu.java.bean.CallbackArg;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -85,7 +86,7 @@ public class AlertTextArea extends AbstractAlertInput