Compare commits
9
Commits
master
..
fa71f5fc21
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa71f5fc21 | ||
|
|
8d40522be0 | ||
|
|
0ab2b755e9 | ||
|
|
0f8b23be91 | ||
|
|
0457ffc432 | ||
|
|
57e6b13292 | ||
|
|
b55a66d6df | ||
|
|
867c5f6602 | ||
|
|
0a5bb393cb |
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.imyeyu.fx.ui</groupId>
|
<groupId>com.imyeyu.fx.ui</groupId>
|
||||||
<artifactId>timi-fx-ui</artifactId>
|
<artifactId>timi-fx-ui</artifactId>
|
||||||
<version>0.0.3</version>
|
<version>0.0.4</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<fx.version>25.0.3</fx.version>
|
<fx.version>25.0.3</fx.version>
|
||||||
@@ -133,12 +133,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.fx</groupId>
|
<groupId>com.imyeyu.fx</groupId>
|
||||||
<artifactId>timi-fx</artifactId>
|
<artifactId>timi-fx</artifactId>
|
||||||
<version>0.0.5</version>
|
<version>0.0.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.fx.icon</groupId>
|
<groupId>com.imyeyu.fx.icon</groupId>
|
||||||
<artifactId>timi-fx-icon</artifactId>
|
<artifactId>timi-fx-icon</artifactId>
|
||||||
<version>0.0.2</version>
|
<version>0.0.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.lang</groupId>
|
<groupId>com.imyeyu.lang</groupId>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.imyeyu.fx.ui;
|
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.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
@@ -66,7 +66,7 @@ public class ScreenIdentify extends Stage implements TimiFXUI {
|
|||||||
public void showIdentify() {
|
public void showIdentify() {
|
||||||
show();
|
show();
|
||||||
|
|
||||||
List<Screen> screens = ScreenFX.SCREENS;
|
List<Screen> screens = Screens.all();
|
||||||
for (int i = 0; i < screens.size(); i++) {
|
for (int i = 0; i < screens.size(); i++) {
|
||||||
showingIdentifyList.add(new Identify(screens.get(i), i));
|
showingIdentifyList.add(new Identify(screens.get(i), i));
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ public class ScreenIdentify extends Stage implements TimiFXUI {
|
|||||||
|
|
||||||
getContent().setAll(text);
|
getContent().setAll(text);
|
||||||
getScene().setFill(BLACK);
|
getScene().setFill(BLACK);
|
||||||
getScene().getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(getScene());
|
||||||
sizeToScene();
|
sizeToScene();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
package com.imyeyu.fx.ui;
|
package com.imyeyu.fx.ui;
|
||||||
|
|
||||||
import com.imyeyu.fx.utils.BgFill;
|
import com.imyeyu.fx.utils.BorderBuilder;
|
||||||
import com.imyeyu.fx.utils.BorderStroke;
|
import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
|
||||||
|
import com.imyeyu.fx.utils.layout.Layout;
|
||||||
import com.imyeyu.lang.multi.ResourcesMultilingual;
|
import com.imyeyu.lang.multi.ResourcesMultilingual;
|
||||||
|
import com.sun.javafx.css.StyleManager;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.VPos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.SeparatorMenuItem;
|
import javafx.scene.control.SeparatorMenuItem;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
import javafx.scene.effect.DropShadow;
|
import javafx.scene.effect.DropShadow;
|
||||||
import javafx.scene.layout.Background;
|
import javafx.scene.layout.Background;
|
||||||
import javafx.scene.layout.Border;
|
import javafx.scene.layout.Border;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @version 2024-04-13 14:18
|
* @version 2024-04-13 14:18
|
||||||
@@ -22,14 +29,55 @@ public interface TimiFXUI {
|
|||||||
/** 静态资源路径 */
|
/** 静态资源路径 */
|
||||||
String RESOURCE = "/timifx/";
|
String RESOURCE = "/timifx/";
|
||||||
|
|
||||||
|
String RESOURCE_STYLE = RESOURCE + "/style";
|
||||||
|
|
||||||
/** 样式文件 */
|
/** 样式文件 */
|
||||||
String CSS_STYLE = RESOURCE + "style.css";
|
String CSS_STYLE = resource("style/style.css");
|
||||||
|
|
||||||
|
/** 控件默认样式文件 */
|
||||||
|
String CSS_USER_AGENT = resource("style/user-agent.css");
|
||||||
|
|
||||||
/** 全局字体替换 */
|
/** 全局字体替换 */
|
||||||
String CSS_FONT = RESOURCE + "font.css";
|
String CSS_FONT = resource("style/font.css");
|
||||||
|
|
||||||
ResourcesMultilingual MULTILINGUAL = new ResourcesMultilingual();
|
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 {
|
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 {
|
interface BG {
|
||||||
|
|
||||||
/** FX 默认背景(#F4F4F4) */
|
/** 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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建通用标题标签
|
* 构建通用标题标签
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.java.bean.CallbackArgReturn;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.geometry.Bounds;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Pos;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.layout.TilePane;
|
|
||||||
import javafx.stage.Popup;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多选选择器,文本框弹出复选框组件进行多项选择
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2021-12-29 17:05
|
|
||||||
*/
|
|
||||||
public class CheckBoxPicker<T> extends TextField implements TimiFXUI {
|
|
||||||
|
|
||||||
/** 数据列表 */
|
|
||||||
@Getter
|
|
||||||
private final ObservableList<T> items;
|
|
||||||
private final CheckBoxListPopup<T> checkBoxListPopup;
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public CheckBoxPicker() {
|
|
||||||
items = FXCollections.observableList(new ArrayList<>());
|
|
||||||
|
|
||||||
checkBoxListPopup = new CheckBoxListPopup<>(items);
|
|
||||||
|
|
||||||
setEditable(false);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
setOnMouseClicked(e -> {
|
|
||||||
Bounds b = localToScreen(getLayoutBounds());
|
|
||||||
checkBoxListPopup.show(this, b.getMinX() - 5, b.getMaxY() - 6);
|
|
||||||
});
|
|
||||||
|
|
||||||
checkBoxListPopup.root.prefWidthProperty().bind(widthProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置复选框工厂,工厂入参数据对象,返回复选框组件
|
|
||||||
*
|
|
||||||
* @param factory 复选框工厂
|
|
||||||
*/
|
|
||||||
public void setCheckBoxFactory(CallbackArgReturn<T, CheckBox> factory) {
|
|
||||||
checkBoxListPopup.checkBoxFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取已选项
|
|
||||||
*
|
|
||||||
* @return 已选项
|
|
||||||
*/
|
|
||||||
public ObservableList<T> getSelectedItems() {
|
|
||||||
return checkBoxListPopup.selectedItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 复选框列表弹窗
|
|
||||||
*
|
|
||||||
* @param <T> 数据类型
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2021-12-29 19:40
|
|
||||||
*/
|
|
||||||
private static class CheckBoxListPopup<T> extends Popup implements TimiFXUI {
|
|
||||||
|
|
||||||
private static final Insets PADDING = new Insets(6, 8, 6, 8);
|
|
||||||
|
|
||||||
private final TilePane root;
|
|
||||||
private final Map<T, CheckBox> cache; // 数据映射缓存
|
|
||||||
|
|
||||||
final ObservableList<T> selectedItems;
|
|
||||||
CallbackArgReturn<T, CheckBox> checkBoxFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认构造
|
|
||||||
*
|
|
||||||
* @param items 数据列表
|
|
||||||
*/
|
|
||||||
public CheckBoxListPopup(ObservableList<T> items) {
|
|
||||||
cache = new HashMap<>();
|
|
||||||
selectedItems = FXCollections.observableList(new ArrayList<>());
|
|
||||||
|
|
||||||
root = new TilePane();
|
|
||||||
root.setHgap(8);
|
|
||||||
root.setEffect(Shadow.POPUP);
|
|
||||||
root.setBorder(Stroke.DEFAULT);
|
|
||||||
root.setPadding(PADDING);
|
|
||||||
root.setMinWidth(300);
|
|
||||||
root.setBackground(BG.DEFAULT);
|
|
||||||
root.setTileAlignment(Pos.CENTER_LEFT);
|
|
||||||
|
|
||||||
setAutoHide(true);
|
|
||||||
getContent().add(root);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
// 列表更新
|
|
||||||
items.addListener((ListChangeListener<T>) c -> {
|
|
||||||
if (c.next()) {
|
|
||||||
if (c.wasAdded()) {
|
|
||||||
// 添加
|
|
||||||
List<? extends T> list = c.getAddedSubList();
|
|
||||||
for (T t : list) {
|
|
||||||
CheckBox box;
|
|
||||||
if (checkBoxFactory != null) {
|
|
||||||
box = checkBoxFactory.handler(t);
|
|
||||||
} else {
|
|
||||||
box = new CheckBox(t.toString());
|
|
||||||
}
|
|
||||||
box.selectedProperty().addListener((obs, o, isSelected) -> {
|
|
||||||
if (isSelected) {
|
|
||||||
selectedItems.add(t);
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cache.put(t, box);
|
|
||||||
root.getChildren().add(box);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.wasRemoved()) {
|
|
||||||
// 移除
|
|
||||||
List<? extends T> list = c.getRemoved();
|
|
||||||
for (T t : list) {
|
|
||||||
root.getChildren().remove(cache.get(t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,9 @@ package com.imyeyu.fx.ui.components;
|
|||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
import com.imyeyu.fx.TimiFX;
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.Nodes;
|
||||||
import com.imyeyu.java.bean.Callback;
|
import com.imyeyu.java.bean.Callback;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import com.sun.javafx.scene.control.DatePickerContent;
|
import com.sun.javafx.scene.control.DatePickerContent;
|
||||||
@@ -36,6 +38,10 @@ import java.time.LocalTime;
|
|||||||
public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorful {
|
public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorful {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "date-time-picker";
|
private static final String STYLE_CLASS = "date-time-picker";
|
||||||
|
private static final String STYLE_CLASS_TIME_PANE = "date-time-picker-time-pane";
|
||||||
|
private static final String STYLE_CLASS_TIME_BOX = "date-time-picker-time-box";
|
||||||
|
private static final String STYLE_CLASS_NOW = "date-time-picker-now";
|
||||||
|
private static final String STYLE_CLASS_CLEAR = "date-time-picker-clear";
|
||||||
|
|
||||||
/** 日期选择器 */
|
/** 日期选择器 */
|
||||||
@Getter
|
@Getter
|
||||||
@@ -49,6 +55,8 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
|
|||||||
|
|
||||||
/** 默认构造器 */
|
/** 默认构造器 */
|
||||||
public DateTimePicker() {
|
public DateTimePicker() {
|
||||||
|
getStylesheets().add(DateTimePicker.class.getResource(RESOURCE + "style/components/date-time-picker.css").toExternalForm());
|
||||||
|
|
||||||
value = new SimpleLongProperty(-1);
|
value = new SimpleLongProperty(-1);
|
||||||
|
|
||||||
// 时间选择
|
// 时间选择
|
||||||
@@ -56,22 +64,22 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
|
|||||||
minute = new ListView<>();
|
minute = new ListView<>();
|
||||||
second = new ListView<>();
|
second = new ListView<>();
|
||||||
|
|
||||||
hour.getStyleClass().add(CSS.BORDER_RB);
|
hour.setBorder(Stroke.RB);
|
||||||
minute.getStyleClass().add(CSS.BORDER_RB);
|
minute.setBorder(Stroke.RB);
|
||||||
second.getStyleClass().add(CSS.BORDER_B);
|
second.setBorder(Stroke.BOTTOM);
|
||||||
|
|
||||||
GridPane hmsPane = new GridPane();
|
GridPane hmsPane = new GridPane();
|
||||||
|
hmsPane.getStyleClass().add(STYLE_CLASS_TIME_BOX);
|
||||||
hmsPane.addRow(0, hour, minute, second);
|
hmsPane.addRow(0, hour, minute, second);
|
||||||
|
|
||||||
Button now = new Button(TimiFXUI.MULTILINGUAL.text("now_tick"));
|
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);
|
timePane = new BorderPane(hmsPane);
|
||||||
timePane.setBorder(Stroke.EX_LEFT);
|
timePane.getStylesheets().add(DateTimePicker.class.getResource(RESOURCE + "style/components/date-time-picker.css").toExternalForm());
|
||||||
timePane.setEffect(Shadow.IMAGE);
|
timePane.getStyleClass().add(STYLE_CLASS_TIME_PANE);
|
||||||
timePane.setPrefWidth(140);
|
timePane.setPrefWidth(140);
|
||||||
timePane.setBackground(BG.DEFAULT);
|
|
||||||
timePane.setTranslateY(-1);
|
|
||||||
timePane.setBottom(now);
|
timePane.setBottom(now);
|
||||||
BorderPane.setAlignment(now, Pos.CENTER_RIGHT);
|
BorderPane.setAlignment(now, Pos.CENTER_RIGHT);
|
||||||
|
|
||||||
@@ -105,8 +113,9 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
|
|||||||
// 失焦关闭而非选择后关闭
|
// 失焦关闭而非选择后关闭
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
IconButton clear = new IconButton(TimiFXIcon.fromName("FAIL", GRAY));
|
IconButton clear = new IconButton(TimiFXIcon.get(TimiIcon.FAIL, GRAY));
|
||||||
clear.getStyleClass().add(CSS.BORDER_ALL);
|
clear.setBorder(Stroke.DEFAULT);
|
||||||
|
clear.getStyleClass().add(STYLE_CLASS_CLEAR);
|
||||||
clear.translateXProperty().bind(widthProperty().subtract(40));
|
clear.translateXProperty().bind(widthProperty().subtract(40));
|
||||||
clear.setTranslateY(15);
|
clear.setTranslateY(15);
|
||||||
clear.visibleProperty().bind(valueProperty().isNotNull());
|
clear.visibleProperty().bind(valueProperty().isNotNull());
|
||||||
@@ -179,9 +188,9 @@ public class DateTimePicker extends Region implements TimiFXUI, TimiFXUI.Colorfu
|
|||||||
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
||||||
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
||||||
|
|
||||||
TimiFX.hoverFocus(hour);
|
Nodes.requestFocusOnHover(hour);
|
||||||
TimiFX.hoverFocus(minute);
|
Nodes.requestFocusOnHover(minute);
|
||||||
TimiFX.hoverFocus(second);
|
Nodes.requestFocusOnHover(second);
|
||||||
|
|
||||||
// 此刻
|
// 此刻
|
||||||
now.setOnAction(e -> setValue(Time.now()));
|
now.setOnAction(e -> setValue(Time.now()));
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.ObservableUtils;
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.task.RunAsync;
|
import com.imyeyu.fx.task.RunAsync;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertButton;
|
import com.imyeyu.fx.ui.components.alert.AlertButton;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertTextField;
|
import com.imyeyu.fx.ui.components.alert.AlertTextField;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
||||||
|
import com.imyeyu.fx.utils.Observables;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.CallbackArgReturn;
|
import com.imyeyu.java.bean.CallbackArgReturn;
|
||||||
@@ -40,7 +41,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-05-26 14:32
|
* @since 2022-05-26 14:32
|
||||||
*/
|
*/
|
||||||
public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
|
public class FileTreeView extends TreeView<File> implements TimiFXUI.Colorful {
|
||||||
|
|
||||||
/** 正在查找节点监听 */
|
/** 正在查找节点监听 */
|
||||||
protected final BooleanBinding findingItem;
|
protected final BooleanBinding findingItem;
|
||||||
@@ -64,8 +65,8 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
|
|||||||
setCellFactory(cell -> new TreeCell<>() {
|
setCellFactory(cell -> new TreeCell<>() {
|
||||||
|
|
||||||
final Label loading = new Label(TimiFXUI.MULTILINGUAL.text("loading"));
|
final Label loading = new Label(TimiFXUI.MULTILINGUAL.text("loading"));
|
||||||
final Text iconFile = TimiFXIcon.fromName("FILE");
|
final Text iconFile = TimiFXIcon.get(TimiIcon.FILE);
|
||||||
final Text iconDirectory = TimiFXIcon.fromName("FOLDER");
|
final Text iconDirectory = TimiFXIcon.get(TimiIcon.FOLDER);
|
||||||
|
|
||||||
{
|
{
|
||||||
iconFile.fillProperty().bind(Bindings.when(FileTreeView.this.focusedProperty().and(selectedProperty())).then(GRAY_WHITE).otherwise(GRAY));
|
iconFile.fillProperty().bind(Bindings.when(FileTreeView.this.focusedProperty().and(selectedProperty())).then(GRAY_WHITE).otherwise(GRAY));
|
||||||
@@ -94,10 +95,10 @@ public class FileTreeView extends XTreeView<File> 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 menuRename = new MenuItem(TimiFXUI.MULTILINGUAL.text("rename"));
|
||||||
MenuItem menuRefresh = new MenuItem(TimiFXUI.MULTILINGUAL.text("refresh"), TimiFXIcon.fromName("REFRESH"));
|
MenuItem menuRefresh = new MenuItem(TimiFXUI.MULTILINGUAL.text("refresh"), TimiFXIcon.get(TimiIcon.REFRESH));
|
||||||
MenuItem menuDestroy = new MenuItem(TimiFXUI.MULTILINGUAL.text("delete"), TimiFXIcon.fromName("FAIL", RED));
|
MenuItem menuDestroy = new MenuItem(TimiFXUI.MULTILINGUAL.text("delete"), TimiFXIcon.get(TimiIcon.FAIL, RED));
|
||||||
|
|
||||||
setContextMenu(new ContextMenu(menuMkdir, menuRename, menuRefresh, TimiFXUI.sep(), menuDestroy));
|
setContextMenu(new ContextMenu(menuMkdir, menuRename, menuRefresh, TimiFXUI.sep(), menuDestroy));
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ public class FileTreeView extends XTreeView<File> implements TimiFXUI.Colorful {
|
|||||||
menuMkdir.setOnAction(e -> mkdir(getSelectionModel().getSelectedItem()));
|
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()));
|
menuRename.setOnAction(e -> rename(getSelectionModel().getSelectedItem()));
|
||||||
|
|
||||||
// 刷新
|
// 刷新
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import javafx.scene.control.Skin;
|
||||||
|
import javafx.scene.control.Slider;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带填充轨道的滑动条
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-07-25
|
||||||
|
*/
|
||||||
|
public class FilledSlider extends Slider implements TimiFXUI {
|
||||||
|
|
||||||
|
/** 组件样式 */
|
||||||
|
static final String STYLE_CLASS = "filled-slider";
|
||||||
|
|
||||||
|
/** 默认构造,范围 [0, 1],默认值 0 */
|
||||||
|
public FilledSlider() {
|
||||||
|
this(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准构造
|
||||||
|
*
|
||||||
|
* @param min 最小值
|
||||||
|
* @param max 最大值
|
||||||
|
* @param value 当前值
|
||||||
|
*/
|
||||||
|
public FilledSlider(double min, double max, double value) {
|
||||||
|
super(min, max, value);
|
||||||
|
getStyleClass().add(STYLE_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Skin<?> createDefaultSkin() {
|
||||||
|
return new FilledSliderSkin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Objects.requireNonNull(FilledSlider.class.getResource(RESOURCE + "style/components/filled-slider.css")).toExternalForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
|
import com.imyeyu.java.ref.Ref;
|
||||||
|
import javafx.scene.control.ProgressBar;
|
||||||
|
import javafx.scene.control.skin.SliderSkin;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填充轨道滑动条皮肤
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-07-25
|
||||||
|
*/
|
||||||
|
class FilledSliderSkin extends SliderSkin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造皮肤
|
||||||
|
*
|
||||||
|
* @param control 控件
|
||||||
|
*/
|
||||||
|
FilledSliderSkin(FilledSlider control) {
|
||||||
|
super(control);
|
||||||
|
try {
|
||||||
|
StackPane track = Ref.getFieldValue(this, "track", StackPane.class);
|
||||||
|
ProgressBar pb = new ProgressBar();
|
||||||
|
pb.progressProperty().bind(control.valueProperty().subtract(control.minProperty()).divide(control.maxProperty().subtract(control.minProperty())));
|
||||||
|
pb.prefWidthProperty().bind(track.widthProperty());
|
||||||
|
pb.setMouseTransparent(true);
|
||||||
|
track.getChildren().addFirst(pb);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-8
@@ -21,21 +21,22 @@ import java.util.regex.Pattern;
|
|||||||
* 超链标签
|
* 超链标签
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* new XHyperlink("个人博客", "<a href="https://www.imyeyu.net">https://www.imyeyu.net</a>");
|
* new Hyperlink("个人博客", "<a href="https://www.imyeyu.net">https://www.imyeyu.net</a>");
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-08-30 10:51
|
* @since 2022-08-30 10:51
|
||||||
*/
|
*/
|
||||||
public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
public class Hyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
||||||
|
|
||||||
|
private static final String STYLE_CLASS = "x-hyperlink";
|
||||||
private static final Pattern URL_PATTERN = Pattern.compile("https?://(www\\.)?[-a-zA-Z\\d@:%._+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-a-zA-Z\\d()@:%_+.~#?&/=]*)");
|
private static final Pattern URL_PATTERN = Pattern.compile("https?://(www\\.)?[-a-zA-Z\\d@:%._+~#=]{1,256}\\.[a-zA-Z\\d()]{1,6}\\b([-a-zA-Z\\d()@:%_+.~#?&/=]*)");
|
||||||
|
|
||||||
/** 链接监听 */
|
/** 链接监听 */
|
||||||
protected final StringProperty url;
|
protected final StringProperty url;
|
||||||
|
|
||||||
/** 默认构造器 */
|
/** 默认构造器 */
|
||||||
public XHyperlink() {
|
public Hyperlink() {
|
||||||
this("", "");
|
this("", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
*
|
*
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(String url) {
|
public Hyperlink(String url) {
|
||||||
this(url, url);
|
this(url, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
* @param text 显示文本
|
* @param text 显示文本
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(String text, String url) {
|
public Hyperlink(String text, String url) {
|
||||||
this(null, text, url);
|
this(null, text, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,15 +66,14 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
* @param text 显示文本
|
* @param text 显示文本
|
||||||
* @param url 链接
|
* @param url 链接
|
||||||
*/
|
*/
|
||||||
public XHyperlink(Node icon, String text, String url) {
|
public Hyperlink(Node icon, String text, String url) {
|
||||||
super(text);
|
super(text);
|
||||||
|
|
||||||
this.url = new SimpleStringProperty(url);
|
this.url = new SimpleStringProperty(url);
|
||||||
|
|
||||||
|
getStyleClass().add(STYLE_CLASS);
|
||||||
setCursor(Cursor.HAND);
|
setCursor(Cursor.HAND);
|
||||||
setGraphic(icon);
|
setGraphic(icon);
|
||||||
setTextFill(FOCUSED_DEFAULT);
|
|
||||||
underlineProperty().bind(hoverProperty());
|
|
||||||
|
|
||||||
addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
|
addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
|
||||||
if (e.getButton() == MouseButton.PRIMARY) {
|
if (e.getButton() == MouseButton.PRIMARY) {
|
||||||
@@ -130,4 +130,9 @@ public class XHyperlink extends Label implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
public StringProperty urlProperty() {
|
public StringProperty urlProperty() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Hyperlink.class.getResource(RESOURCE + "style/components/hyperlink.css").toExternalForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.Nodes;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
@@ -15,6 +15,8 @@ import javafx.scene.image.Image;
|
|||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图标按钮,可选图片、SVG 路径或 {@link com.imyeyu.fx.icon.TimiFXIcon} 的字体图标
|
* 图标按钮,可选图片、SVG 路径或 {@link com.imyeyu.fx.icon.TimiFXIcon} 的字体图标
|
||||||
*
|
*
|
||||||
@@ -118,7 +120,7 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
if (node != null) {
|
if (node != null) {
|
||||||
setGraphic(node);
|
setGraphic(node);
|
||||||
}
|
}
|
||||||
TimiFX.hoverOpacity(this);
|
Nodes.bindHoverOpacity(this);
|
||||||
|
|
||||||
// 自适应尺寸、单独图标、图标文本混合时设置不同的内边距
|
// 自适应尺寸、单独图标、图标文本混合时设置不同的内边距
|
||||||
paddingProperty().bind(Bindings.createObjectBinding(() -> {
|
paddingProperty().bind(Bindings.createObjectBinding(() -> {
|
||||||
@@ -140,20 +142,8 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
* @return 本实例
|
* @return 本实例
|
||||||
*/
|
*/
|
||||||
public IconButton withBackground() {
|
public IconButton withBackground() {
|
||||||
return withBackground(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加按钮背景
|
|
||||||
*
|
|
||||||
* @param borderClass 边框类
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public IconButton withBackground(String borderClass) {
|
|
||||||
getStyleClass().add(CSS.BG_BUTTON);
|
getStyleClass().add(CSS.BG_BUTTON);
|
||||||
if (TimiJava.isNotEmpty(borderClass)) {
|
setBorder(Stroke.DEFAULT);
|
||||||
getStyleClass().add(borderClass);
|
|
||||||
}
|
|
||||||
opacityProperty().unbind();
|
opacityProperty().unbind();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -169,7 +159,7 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前是否自适应尺寸,ture 时图标尺寸决定组件尺寸
|
* 获取当前是否自适应尺寸,true 时图标尺寸决定组件尺寸
|
||||||
*
|
*
|
||||||
* @return true 为自适应尺寸
|
* @return true 为自适应尺寸
|
||||||
*/
|
*/
|
||||||
@@ -178,7 +168,7 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置是否自适应尺寸,ture 时图标尺寸决定组件尺寸
|
* 设置是否自适应尺寸,true 时图标尺寸决定组件尺寸
|
||||||
*
|
*
|
||||||
* @param autoSize true 为自适应尺寸
|
* @param autoSize true 为自适应尺寸
|
||||||
*/
|
*/
|
||||||
@@ -205,4 +195,9 @@ public class IconButton extends Button implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
iconTextPadding = new Insets(tv, h, tv, h);
|
iconTextPadding = new Insets(tv, h, tv, h);
|
||||||
return defaultSkin;
|
return defaultSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Objects.requireNonNull(IconButton.class.getResource(RESOURCE + "style/components/icon-button.css")).toExternalForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.utils.BgFill;
|
import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
import com.imyeyu.utils.Collect;
|
import com.imyeyu.utils.Collect;
|
||||||
@@ -29,8 +30,12 @@ import javafx.stage.Stage;
|
|||||||
import javafx.stage.StageStyle;
|
import javafx.stage.StageStyle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TimiFXIcon} 的图标选择器(标签搜索需要联网)
|
* {@link TimiFXIcon} 的图标选择器(标签搜索需要联网)
|
||||||
@@ -58,7 +63,7 @@ public class IconPicker extends TextField implements TimiFXUI {
|
|||||||
if (TimiJava.isEmpty(value)) {
|
if (TimiJava.isEmpty(value)) {
|
||||||
root.setLeft(null);
|
root.setLeft(null);
|
||||||
} else {
|
} else {
|
||||||
Text icon = TimiFXIcon.fromName(value);
|
Text icon = TimiFXIcon.get(TimiIcon.valueOf(value));
|
||||||
BorderPane.setMargin(icon, new Insets(0, 2, 0, 0));
|
BorderPane.setMargin(icon, new Insets(0, 2, 0, 0));
|
||||||
BorderPane.setAlignment(icon, Pos.CENTER);
|
BorderPane.setAlignment(icon, Pos.CENTER);
|
||||||
root.setLeft(icon);
|
root.setLeft(icon);
|
||||||
@@ -81,7 +86,7 @@ public class IconPicker extends TextField implements TimiFXUI {
|
|||||||
if (newToggle == null) {
|
if (newToggle == null) {
|
||||||
clear();
|
clear();
|
||||||
} else if (newToggle instanceof ToggleIcon icon) {
|
} 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 图标图像
|
* @return 图标图像
|
||||||
*/
|
*/
|
||||||
public Image getValue() {
|
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 ToggleGroup group;
|
||||||
final List<ToggleIcon> icons;
|
final List<ToggleIcon> icons;
|
||||||
final Map<String, Character> nameMapping = TimiFXIcon.getNameMapping();
|
final Map<TimiIcon, String> unicodeMap = Arrays.stream(TimiIcon.values()).collect(Collectors.toMap(Function.identity(), TimiIcon::getUnicode));
|
||||||
|
|
||||||
public IconPickerPopup() {
|
public IconPickerPopup() {
|
||||||
// 图标
|
// 图标
|
||||||
@@ -131,13 +136,12 @@ public class IconPicker extends TextField implements TimiFXUI {
|
|||||||
|
|
||||||
icons = new ArrayList<>();
|
icons = new ArrayList<>();
|
||||||
group = new ToggleGroup();
|
group = new ToggleGroup();
|
||||||
Map<String, Character> items = Collect.sortMapByStringKeyASC(nameMapping);
|
Map<TimiIcon, String> items = Collect.sortMap(unicodeMap, Comparator.comparing(Enum::name));
|
||||||
for (Map.Entry<String, Character> item : items.entrySet()) {
|
for (Map.Entry<TimiIcon, String> item : items.entrySet()) {
|
||||||
icons.add(new ToggleIcon(group, item.getKey()));
|
icons.add(new ToggleIcon(group, item.getKey()));
|
||||||
}
|
}
|
||||||
tile.getChildren().addAll(icons);
|
tile.getChildren().addAll(icons);
|
||||||
|
focusedProperty().addListener((_, _, isFocused) -> {
|
||||||
focusedProperty().addListener((obs, o, isFocused) -> {
|
|
||||||
if (!isFocused) {
|
if (!isFocused) {
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
@@ -156,12 +160,12 @@ public class IconPicker extends TextField implements TimiFXUI {
|
|||||||
setPadding(new Insets(6, 8, 6, 8));
|
setPadding(new Insets(6, 8, 6, 8));
|
||||||
setFitToWidth(true);
|
setFitToWidth(true);
|
||||||
|
|
||||||
SmoothScroll.scrollPane(this);
|
SmoothScroll.pane.install(this);
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
scene.setFill(null);
|
scene.setFill(null);
|
||||||
scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(scene);
|
||||||
setScene(scene);
|
setScene(scene);
|
||||||
setWidth(360);
|
setWidth(360);
|
||||||
setHeight(240);
|
setHeight(240);
|
||||||
@@ -177,16 +181,16 @@ public class IconPicker extends TextField implements TimiFXUI {
|
|||||||
*/
|
*/
|
||||||
private static class ToggleIcon extends ToggleButton {
|
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("");
|
super("");
|
||||||
this.name = name;
|
this.value = value;
|
||||||
|
|
||||||
setGraphic(TimiFXIcon.fromName(name));
|
setGraphic(TimiFXIcon.get(value, 16));
|
||||||
getStyleClass().clear();
|
getStyleClass().clear();
|
||||||
managedProperty().bind(visibleProperty());
|
managedProperty().bind(visibleProperty());
|
||||||
borderProperty().bind(Bindings.when(hoverProperty()).then(Stroke.FOCUSED).otherwise(Stroke.TP));
|
borderProperty().bind(Bindings.when(hoverProperty()).then(Stroke.FOCUSED).otherwise(Stroke.TP));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.java.bean.CallbackArgReturn;
|
import com.imyeyu.java.bean.CallbackArgReturn;
|
||||||
import javafx.beans.property.DoubleProperty;
|
import javafx.beans.property.DoubleProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
@@ -16,7 +17,7 @@ import lombok.Setter;
|
|||||||
* @since 2022-08-09 10:48
|
* @since 2022-08-09 10:48
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class LabelProgressBar extends StackPane {
|
public class LabelProgressBar extends StackPane implements TimiFXUI {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "label-progress-bar";
|
private static final String STYLE_CLASS = "label-progress-bar";
|
||||||
|
|
||||||
@@ -32,6 +33,8 @@ public class LabelProgressBar extends StackPane {
|
|||||||
|
|
||||||
/** 默认构造 */
|
/** 默认构造 */
|
||||||
public LabelProgressBar() {
|
public LabelProgressBar() {
|
||||||
|
getStylesheets().add(LabelProgressBar.class.getResource(RESOURCE + "style/components/label-progress-bar.css").toExternalForm());
|
||||||
|
|
||||||
label = new Label();
|
label = new Label();
|
||||||
bar = new ProgressBar();
|
bar = new ProgressBar();
|
||||||
bar.prefWidthProperty().bind(widthProperty());
|
bar.prefWidthProperty().bind(widthProperty());
|
||||||
|
|||||||
@@ -1,236 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.control.TitledPane;
|
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.control.ToggleGroup;
|
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 纵向导航组件,可实现二级导航,折叠导航
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-02-17 00:11
|
|
||||||
*/
|
|
||||||
public class Navigation extends ScrollPane implements TimiFXUI {
|
|
||||||
|
|
||||||
/** 导航数据列表 */
|
|
||||||
@Getter
|
|
||||||
protected final ObservableList<ToggleButton> items;
|
|
||||||
|
|
||||||
/** 已选中监听 */
|
|
||||||
protected final ObjectProperty<ToggleButton> selectedItem;
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public Navigation() {
|
|
||||||
items = FXCollections.observableArrayList();
|
|
||||||
selectedItem = new SimpleObjectProperty<>();
|
|
||||||
|
|
||||||
VBox root = new VBox();
|
|
||||||
root.setBorder(Stroke.BOTTOM);
|
|
||||||
|
|
||||||
getStyleClass().addAll("navigation", "sp-border");
|
|
||||||
setMaxWidth(Double.MAX_VALUE);
|
|
||||||
setVbarPolicy(ScrollBarPolicy.NEVER);
|
|
||||||
setFitToWidth(true);
|
|
||||||
setContent(root);
|
|
||||||
|
|
||||||
SmoothScroll.scrollPaneV(this);
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
ToggleGroup group = new ToggleGroup();
|
|
||||||
|
|
||||||
// 主动选择(代码触发)
|
|
||||||
selectedItem.addListener((obs, o, newSelectedItem) -> group.selectToggle(newSelectedItem));
|
|
||||||
|
|
||||||
// 被动选择(操作触发)
|
|
||||||
group.selectedToggleProperty().addListener((obs, o, toggle) -> {
|
|
||||||
if (toggle instanceof ToggleButton btn) {
|
|
||||||
selectedItem.set(btn);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ObservableList<Node> children = root.getChildren();
|
|
||||||
|
|
||||||
// 响应 TimiFXUI
|
|
||||||
items.addListener((ListChangeListener<ToggleButton>) c -> {
|
|
||||||
while (c.next()) {
|
|
||||||
if (c.wasAdded()) {
|
|
||||||
// 添加
|
|
||||||
List<? extends ToggleButton> list = c.getAddedSubList();
|
|
||||||
for (ToggleButton toggleButton : list) {
|
|
||||||
toggleButton.setMaxWidth(Double.MAX_VALUE);
|
|
||||||
toggleButton.getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
|
|
||||||
toggleButton.addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
|
|
||||||
|
|
||||||
if (toggleButton.getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
// 存在所属组
|
|
||||||
if (!children.contains(pane)) {
|
|
||||||
// 未添加组
|
|
||||||
children.add(pane);
|
|
||||||
}
|
|
||||||
if (pane.getContent() instanceof VBox box) {
|
|
||||||
box.getChildren().add(toggleButton);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 单独项
|
|
||||||
if (!children.isEmpty()) {
|
|
||||||
if (children.getLast() instanceof TitledPane) {
|
|
||||||
// 上一项是组导航,添加上边框
|
|
||||||
toggleButton.getStyleClass().add("after-group");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
children.add(toggleButton);
|
|
||||||
}
|
|
||||||
// 归组
|
|
||||||
group.getToggles().add(toggleButton);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.wasRemoved()) {
|
|
||||||
// 移除
|
|
||||||
List<? extends ToggleButton> list = c.getRemoved();
|
|
||||||
for (ToggleButton toggleButton : list) {
|
|
||||||
if (toggleButton.getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
// 存在所属组
|
|
||||||
if (pane.getContent() instanceof VBox box) {
|
|
||||||
box.getChildren().remove(toggleButton);
|
|
||||||
if (box.getChildren().isEmpty()) {
|
|
||||||
// 该组已没有列表项
|
|
||||||
children.remove(box);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 单独项
|
|
||||||
children.remove(toggleButton);
|
|
||||||
}
|
|
||||||
// 从组移除
|
|
||||||
group.getToggles().remove(toggleButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航按钮
|
|
||||||
*
|
|
||||||
* @param buttons 导航按钮
|
|
||||||
*/
|
|
||||||
public void add(ToggleButton... buttons) {
|
|
||||||
getItems().addAll(buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加默认没有展开的导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(String title, ToggleButton... buttons) {
|
|
||||||
return addGroup(title, false, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加默认展开的导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addExpandedGroup(String title, ToggleButton... buttons) {
|
|
||||||
return addGroup(title, true, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航组
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @param isExpanded true 为默认展开
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 构造的折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(String title, boolean isExpanded, ToggleButton... buttons) {
|
|
||||||
TitledPane pane = new TitledPane();
|
|
||||||
pane.setText(title);
|
|
||||||
return addGroup(pane, isExpanded, buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加导航组
|
|
||||||
*
|
|
||||||
* @param pane 所属组
|
|
||||||
* @param isExpanded true 为默认展开
|
|
||||||
* @param buttons 导航项
|
|
||||||
* @return 原折叠面板
|
|
||||||
*/
|
|
||||||
public TitledPane addGroup(TitledPane pane, boolean isExpanded, ToggleButton... buttons) {
|
|
||||||
VBox content = new VBox();
|
|
||||||
content.setPadding(Insets.EMPTY);
|
|
||||||
|
|
||||||
pane.setContent(content);
|
|
||||||
pane.setExpanded(isExpanded);
|
|
||||||
pane.getStyleClass().add("group-pane");
|
|
||||||
|
|
||||||
for (ToggleButton button : buttons) {
|
|
||||||
button.getProperties().put("OWNER", pane);
|
|
||||||
items.add(button);
|
|
||||||
}
|
|
||||||
return pane;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取该按钮所属组
|
|
||||||
*
|
|
||||||
* @param btn 按钮
|
|
||||||
* @return 所属组,null 时为不属于任何组
|
|
||||||
*/
|
|
||||||
public TitledPane getGroup(ToggleButton btn) {
|
|
||||||
if (btn.getProperties().get("OWNER") instanceof TitledPane pane) {
|
|
||||||
return pane;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前激活导航项
|
|
||||||
*
|
|
||||||
* @param button 导航项
|
|
||||||
*/
|
|
||||||
public void setSelectedItem(ToggleButton button) {
|
|
||||||
selectedItem.set(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前激活的导航项
|
|
||||||
*
|
|
||||||
* @return 当前激活的导航项
|
|
||||||
*/
|
|
||||||
public ToggleButton getSelectedItem() {
|
|
||||||
return selectedItem.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取激活导航项监听
|
|
||||||
*
|
|
||||||
* @return 激活导航项监听
|
|
||||||
*/
|
|
||||||
public ObjectProperty<ToggleButton> selectedItem() {
|
|
||||||
return selectedItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+24
-10
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
@@ -15,16 +16,18 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.control.ToggleButton;
|
import javafx.scene.control.ToggleButton;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页组件,支持省略页,滚动页,如 [<][1]..[5][6][7][8][9]..[20][>]
|
* 分页组件,支持省略页,滚动页,如 [<][1]..[5][6][7][8][9]..[20][>]
|
||||||
* <pre>
|
* <pre>
|
||||||
* XPagination pagination = new XPagination();
|
* Pagination pagination = new Pagination();
|
||||||
* pagination.setSize(10); // 单页数据量
|
* pagination.setSize(10); // 单页数据量
|
||||||
* pagination.setLength(200); // 总数据量
|
* pagination.setLength(200); // 总数据量
|
||||||
* pagination.indexProperty((obs, o, newIndex) -> {
|
* pagination.indexProperty((obs, o, newIndex) -> {
|
||||||
@@ -36,7 +39,7 @@ import java.util.List;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2021-12-22 15:25
|
* @since 2021-12-22 15:25
|
||||||
*/
|
*/
|
||||||
public class XPagination extends HBox implements TimiFXUI {
|
public class Pagination extends HBox implements TimiFXUI {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "x-pagination";
|
private static final String STYLE_CLASS = "x-pagination";
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
private final IntegerProperty cp; // chunkProperty 页面数量 [1, N]
|
private final IntegerProperty cp; // chunkProperty 页面数量 [1, N]
|
||||||
|
|
||||||
/** 默认构造 */
|
/** 默认构造 */
|
||||||
public XPagination() {
|
public Pagination() {
|
||||||
// 基本参数
|
// 基本参数
|
||||||
lp = new SimpleLongProperty();
|
lp = new SimpleLongProperty();
|
||||||
ip = new SimpleIntegerProperty();
|
ip = new SimpleIntegerProperty();
|
||||||
@@ -77,8 +80,8 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
PageButton tb;
|
PageButton tb;
|
||||||
|
|
||||||
// 上一页
|
// 上一页
|
||||||
prev = new IconButton(TimiFXIcon.fromName("ARROW_1_W")).withBackground();
|
prev = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_1_W)).withBackground();
|
||||||
prev.getStyleClass().add(CSS.BORDER_N);
|
prev.setBorder(Border.EMPTY);
|
||||||
prev.setMaxHeight(Double.MAX_VALUE);
|
prev.setMaxHeight(Double.MAX_VALUE);
|
||||||
prev.disableProperty().bind(ip.isEqualTo(0));
|
prev.disableProperty().bind(ip.isEqualTo(0));
|
||||||
getChildren().add(prev);
|
getChildren().add(prev);
|
||||||
@@ -94,7 +97,7 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
// 2. 总页数大于等于 8,激活下标小于 4(1 - 4 页)
|
// 2. 总页数大于等于 8,激活下标小于 4(1 - 4 页)
|
||||||
tb.visibleProperty().bind(cp.greaterThan(i).and(cp.lessThan(8)).or(cp.greaterThan(7).and(ip.lessThan(4))));
|
tb.visibleProperty().bind(cp.greaterThan(i).and(cp.lessThan(8)).or(cp.greaterThan(7).and(ip.lessThan(4))));
|
||||||
} else {
|
} else {
|
||||||
tb.getStyleClass().add(CSS.BORDER_LR);
|
tb.setBorder(Stroke.V);
|
||||||
}
|
}
|
||||||
pageButtons.add(tb);
|
pageButtons.add(tb);
|
||||||
getChildren().add(tb);
|
getChildren().add(tb);
|
||||||
@@ -147,9 +150,9 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 下一页
|
// 下一页
|
||||||
next = new IconButton(TimiFXIcon.fromName("ARROW_1_E")).withBackground();
|
next = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_1_E)).withBackground();
|
||||||
|
next.setBorder(Border.EMPTY);
|
||||||
next.setMaxHeight(Double.MAX_VALUE);
|
next.setMaxHeight(Double.MAX_VALUE);
|
||||||
next.getStyleClass().add(CSS.BORDER_N);
|
|
||||||
next.disableProperty().bind(ip.isEqualTo(cp.subtract(1)).or(cp.isEqualTo(0)));
|
next.disableProperty().bind(ip.isEqualTo(cp.subtract(1)).or(cp.isEqualTo(0)));
|
||||||
|
|
||||||
getStyleClass().add(STYLE_CLASS);
|
getStyleClass().add(STYLE_CLASS);
|
||||||
@@ -193,6 +196,11 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
next.setOnAction(e -> ip.set(nextI));
|
next.setOnAction(e -> ip.set(nextI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Objects.requireNonNull(Pagination.class.getResource(RESOURCE + "style/components/pagination.css")).toExternalForm();
|
||||||
|
}
|
||||||
|
|
||||||
/** 选择上一页 */
|
/** 选择上一页 */
|
||||||
public void prev() {
|
public void prev() {
|
||||||
prev.fire();
|
prev.fire();
|
||||||
@@ -322,16 +330,22 @@ public class XPagination extends HBox implements TimiFXUI {
|
|||||||
public PageButton() {
|
public PageButton() {
|
||||||
indexProperty = new SimpleIntegerProperty();
|
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());
|
textProperty().bind(indexProperty.add(1).asString());
|
||||||
managedProperty().bind(visibleProperty());
|
managedProperty().bind(visibleProperty());
|
||||||
// 选中更新激活下标
|
// 选中更新激活下标
|
||||||
selectedProperty().addListener((obs, o, isSelected) -> {
|
selectedProperty().addListener((obs, o, isSelected) -> {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
XPagination.this.ip.set(indexProperty.get());
|
Pagination.this.ip.set(indexProperty.get());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Objects.requireNonNull(Pagination.class.getResource(RESOURCE + "style/components/pagination.css")).toExternalForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.java.ref.Ref;
|
|
||||||
import javafx.scene.control.ProgressBar;
|
|
||||||
import javafx.scene.control.Skin;
|
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.control.skin.SliderSkin;
|
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 带有进度的滑动选中,通常是媒体播放进度或音量进度(未对纵向滑动组件测试)
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2021-11-09 21:34
|
|
||||||
*/
|
|
||||||
public class ProgressSlider extends Slider implements TimiFXUI {
|
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "progress-slider";
|
|
||||||
|
|
||||||
/** 默认构造,范围 [0, 1],默认值 0 */
|
|
||||||
public ProgressSlider() {
|
|
||||||
this(0, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准构造
|
|
||||||
*
|
|
||||||
* @param min 最小值
|
|
||||||
* @param max 最大值
|
|
||||||
* @param value 当前值
|
|
||||||
*/
|
|
||||||
public ProgressSlider(double min, double max, double value) {
|
|
||||||
super(min, max, value);
|
|
||||||
getStyleClass().add(STYLE_CLASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Skin<?> createDefaultSkin() {
|
|
||||||
Skin<?> skin = super.createDefaultSkin();
|
|
||||||
if (skin instanceof SliderSkin) {
|
|
||||||
try {
|
|
||||||
StackPane track = Ref.getFieldValue(skin, "track", StackPane.class);
|
|
||||||
ProgressBar pb = new ProgressBar();
|
|
||||||
pb.progressProperty().bind(valueProperty().subtract(minProperty()).divide(maxProperty().subtract(minProperty())));
|
|
||||||
pb.prefWidthProperty().bind(track.widthProperty());
|
|
||||||
pb.setMouseTransparent(true);
|
|
||||||
track.getChildren().addFirst(pb);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return skin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.utils.Nodes;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单选按钮组组件
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-26
|
||||||
|
*/
|
||||||
|
public class RadioButtonGroup extends Control {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮组模式
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-26
|
||||||
|
*/
|
||||||
|
public enum Mode {
|
||||||
|
|
||||||
|
/** 按钮模式 */
|
||||||
|
BUTTON,
|
||||||
|
|
||||||
|
/** 滑块模式 */
|
||||||
|
SLIDER
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根样式 */
|
||||||
|
public static final String STYLE_CLASS = "radio-button-group";
|
||||||
|
|
||||||
|
/** 按钮模式样式 */
|
||||||
|
public static final String STYLE_CLASS_BUTTON_MODE = "button-mode";
|
||||||
|
|
||||||
|
/** 滑块模式样式 */
|
||||||
|
public static final String STYLE_CLASS_SLIDER_MODE = "slider-mode";
|
||||||
|
|
||||||
|
/** 容器样式 */
|
||||||
|
public static final String STYLE_CLASS_BOX = "radio-button-group-box";
|
||||||
|
|
||||||
|
/** 滑块样式 */
|
||||||
|
public static final String STYLE_CLASS_SLIDER = "radio-button-group-slider";
|
||||||
|
|
||||||
|
/** 按钮样式 */
|
||||||
|
public static final String STYLE_CLASS_BUTTON = "radio-button-group-button";
|
||||||
|
|
||||||
|
/** 首按钮样式 */
|
||||||
|
public static final String STYLE_CLASS_FIRST = "first";
|
||||||
|
|
||||||
|
/** 中间按钮样式 */
|
||||||
|
public static final String STYLE_CLASS_MIDDLE = "middle";
|
||||||
|
|
||||||
|
/** 末按钮样式 */
|
||||||
|
public static final String STYLE_CLASS_LAST = "last";
|
||||||
|
|
||||||
|
/** 单按钮样式 */
|
||||||
|
public static final String STYLE_CLASS_SINGLE = "single";
|
||||||
|
|
||||||
|
/** 按钮列表 */
|
||||||
|
@Getter
|
||||||
|
private final ObservableList<ToggleButton> buttons;
|
||||||
|
|
||||||
|
/** 按钮组 */
|
||||||
|
private final ToggleGroup toggleGroup;
|
||||||
|
|
||||||
|
/** 当前选中按钮 */
|
||||||
|
private final ReadOnlyObjectWrapper<ToggleButton> selectedButton;
|
||||||
|
|
||||||
|
/** 当前选中下标 */
|
||||||
|
private final IntegerProperty selectedIndex;
|
||||||
|
|
||||||
|
/** 按钮间距 */
|
||||||
|
private final DoubleProperty spacing;
|
||||||
|
|
||||||
|
/** 布局对齐方式 */
|
||||||
|
private final ObjectProperty<Pos> alignment;
|
||||||
|
|
||||||
|
/** 当前模式 */
|
||||||
|
private final ObjectProperty<Mode> mode;
|
||||||
|
|
||||||
|
/** true 为允许清空选中 */
|
||||||
|
private final BooleanProperty allowClearSelection;
|
||||||
|
|
||||||
|
/** 禁止重复点击清空 */
|
||||||
|
private final EventHandler<MouseEvent> keepSelectionEvent = event -> {
|
||||||
|
if (shouldKeepSelection(event.getSource())) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 禁止通过键盘重复触发清空 */
|
||||||
|
private final EventHandler<KeyEvent> keepSelectionKeyEvent = event -> {
|
||||||
|
if ((event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) && shouldKeepSelection(event.getSource())) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public RadioButtonGroup() {
|
||||||
|
buttons = FXCollections.observableArrayList();
|
||||||
|
toggleGroup = new ToggleGroup();
|
||||||
|
selectedButton = new ReadOnlyObjectWrapper<>();
|
||||||
|
selectedIndex = new SimpleIntegerProperty(-1);
|
||||||
|
spacing = new SimpleDoubleProperty();
|
||||||
|
alignment = new SimpleObjectProperty<>(Pos.CENTER_LEFT);
|
||||||
|
mode = new SimpleObjectProperty<>(Mode.BUTTON);
|
||||||
|
allowClearSelection = new SimpleBooleanProperty();
|
||||||
|
|
||||||
|
getStyleClass().addAll(STYLE_CLASS, STYLE_CLASS_BUTTON_MODE);
|
||||||
|
setFocusTraversable(false);
|
||||||
|
|
||||||
|
initSelectionSync();
|
||||||
|
initButtonsListener();
|
||||||
|
initModeStyleClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化选中同步
|
||||||
|
*/
|
||||||
|
private void initSelectionSync() {
|
||||||
|
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));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedButton.set(null);
|
||||||
|
selectedIndex.set(-1);
|
||||||
|
});
|
||||||
|
selectedIndex.addListener((obs, o, newIndex) -> {
|
||||||
|
int index = newIndex == null ? -1 : newIndex.intValue();
|
||||||
|
if (index < 0) {
|
||||||
|
if (isAllowClearSelection()) {
|
||||||
|
toggleGroup.selectToggle(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (index < buttons.size()) {
|
||||||
|
toggleGroup.selectToggle(buttons.get(index));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化按钮监听
|
||||||
|
*/
|
||||||
|
private void initButtonsListener() {
|
||||||
|
buttons.addListener((ListChangeListener<ToggleButton>) change -> {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasRemoved()) {
|
||||||
|
for (ToggleButton button : change.getRemoved()) {
|
||||||
|
detachButton(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
for (ToggleButton button : change.getAddedSubList()) {
|
||||||
|
attachButton(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syncSelectionState();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化模式样式
|
||||||
|
*/
|
||||||
|
private void initModeStyleClass() {
|
||||||
|
Nodes.bindStyleClass(this, mode.isEqualTo(Mode.SLIDER), STYLE_CLASS_SLIDER_MODE, STYLE_CLASS_BUTTON_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂载按钮到当前组件
|
||||||
|
*
|
||||||
|
* @param button 按钮
|
||||||
|
*/
|
||||||
|
private void attachButton(ToggleButton button) {
|
||||||
|
if (button == null) {
|
||||||
|
throw new IllegalArgumentException("button must not be null");
|
||||||
|
}
|
||||||
|
button.setToggleGroup(toggleGroup);
|
||||||
|
button.addEventFilter(MouseEvent.MOUSE_PRESSED, keepSelectionEvent);
|
||||||
|
button.addEventFilter(KeyEvent.KEY_PRESSED, keepSelectionKeyEvent);
|
||||||
|
button.addEventFilter(KeyEvent.KEY_RELEASED, keepSelectionKeyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载按钮
|
||||||
|
*
|
||||||
|
* @param button 按钮
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步当前选中状态
|
||||||
|
*/
|
||||||
|
private void syncSelectionState() {
|
||||||
|
ToggleButton currentSelectedButton = getSelectedButton();
|
||||||
|
if (currentSelectedButton != null && !buttons.contains(currentSelectedButton)) {
|
||||||
|
if (isAllowClearSelection()) {
|
||||||
|
toggleGroup.selectToggle(null);
|
||||||
|
}
|
||||||
|
else if (!buttons.isEmpty()) {
|
||||||
|
toggleGroup.selectToggle(buttons.getFirst());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = selectedIndex.get();
|
||||||
|
if (index < 0 || buttons.size() <= index) {
|
||||||
|
if (!buttons.isEmpty() && !isAllowClearSelection() && toggleGroup.getSelectedToggle() == null) {
|
||||||
|
toggleGroup.selectToggle(buttons.getFirst());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleGroup.selectToggle(buttons.get(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Skin<?> createDefaultSkin() {
|
||||||
|
return new RadioButtonGroupSkin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加按钮
|
||||||
|
*
|
||||||
|
* @param buttons 按钮列表
|
||||||
|
*/
|
||||||
|
public void addButton(ToggleButton... buttons) {
|
||||||
|
getButtons().addAll(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加文本按钮
|
||||||
|
*
|
||||||
|
* @param text 按钮文本
|
||||||
|
* @return 新增按钮
|
||||||
|
*/
|
||||||
|
public ToggleButton addButton(String text) {
|
||||||
|
ToggleButton button = new ToggleButton(text);
|
||||||
|
getButtons().add(button);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前选中按钮
|
||||||
|
*
|
||||||
|
* @param button 当前选中按钮
|
||||||
|
*/
|
||||||
|
public void setSelectedButton(ToggleButton button) {
|
||||||
|
if (button == null) {
|
||||||
|
if (isAllowClearSelection()) {
|
||||||
|
toggleGroup.selectToggle(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!buttons.contains(button)) {
|
||||||
|
throw new IllegalArgumentException("button must belong to current group");
|
||||||
|
}
|
||||||
|
toggleGroup.selectToggle(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前选中按钮
|
||||||
|
*
|
||||||
|
* @return 当前选中按钮
|
||||||
|
*/
|
||||||
|
public ToggleButton getSelectedButton() {
|
||||||
|
return selectedButton.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前选中按钮属性
|
||||||
|
*
|
||||||
|
* @return 当前选中按钮属性
|
||||||
|
*/
|
||||||
|
public ReadOnlyObjectProperty<ToggleButton> selectedButtonProperty() {
|
||||||
|
return selectedButton.getReadOnlyProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前选中下标
|
||||||
|
*
|
||||||
|
* @param selectedIndex 当前选中下标
|
||||||
|
*/
|
||||||
|
public void setSelectedIndex(int selectedIndex) {
|
||||||
|
this.selectedIndex.set(selectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前选中下标
|
||||||
|
*
|
||||||
|
* @return 当前选中下标
|
||||||
|
*/
|
||||||
|
public int getSelectedIndex() {
|
||||||
|
return selectedIndex.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前选中下标属性
|
||||||
|
*
|
||||||
|
* @return 当前选中下标属性
|
||||||
|
*/
|
||||||
|
public IntegerProperty selectedIndexProperty() {
|
||||||
|
return selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置按钮间距
|
||||||
|
*
|
||||||
|
* @param spacing 按钮间距
|
||||||
|
*/
|
||||||
|
public void setSpacing(double spacing) {
|
||||||
|
this.spacing.set(Math.max(0, spacing));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取按钮间距
|
||||||
|
*
|
||||||
|
* @return 按钮间距
|
||||||
|
*/
|
||||||
|
public double getSpacing() {
|
||||||
|
return spacing.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取按钮间距属性
|
||||||
|
*
|
||||||
|
* @return 按钮间距属性
|
||||||
|
*/
|
||||||
|
public DoubleProperty spacingProperty() {
|
||||||
|
return spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置布局对齐方式
|
||||||
|
*
|
||||||
|
* @param alignment 布局对齐方式
|
||||||
|
*/
|
||||||
|
public void setAlignment(Pos alignment) {
|
||||||
|
this.alignment.set(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取布局对齐方式
|
||||||
|
*
|
||||||
|
* @return 布局对齐方式
|
||||||
|
*/
|
||||||
|
public Pos getAlignment() {
|
||||||
|
return alignment.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取布局对齐方式属性
|
||||||
|
*
|
||||||
|
* @return 布局对齐方式属性
|
||||||
|
*/
|
||||||
|
public ObjectProperty<Pos> alignmentProperty() {
|
||||||
|
return alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前模式
|
||||||
|
*
|
||||||
|
* @param mode 当前模式
|
||||||
|
*/
|
||||||
|
public void setMode(Mode mode) {
|
||||||
|
this.mode.set(mode == null ? Mode.BUTTON : mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前模式
|
||||||
|
*
|
||||||
|
* @return 当前模式
|
||||||
|
*/
|
||||||
|
public Mode getMode() {
|
||||||
|
return mode.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前模式属性
|
||||||
|
*
|
||||||
|
* @return 当前模式属性
|
||||||
|
*/
|
||||||
|
public ObjectProperty<Mode> modeProperty() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否允许清空选中
|
||||||
|
*
|
||||||
|
* @param allowClearSelection true 为允许清空选中
|
||||||
|
*/
|
||||||
|
public void setAllowClearSelection(boolean allowClearSelection) {
|
||||||
|
this.allowClearSelection.set(allowClearSelection);
|
||||||
|
if (!allowClearSelection && toggleGroup.getSelectedToggle() == null && !buttons.isEmpty()) {
|
||||||
|
toggleGroup.selectToggle(buttons.getFirst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否允许清空选中
|
||||||
|
*
|
||||||
|
* @return true 为允许清空选中
|
||||||
|
*/
|
||||||
|
public boolean isAllowClearSelection() {
|
||||||
|
return allowClearSelection.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否允许清空选中属性
|
||||||
|
*
|
||||||
|
* @return 是否允许清空选中属性
|
||||||
|
*/
|
||||||
|
public BooleanProperty allowClearSelectionProperty() {
|
||||||
|
return allowClearSelection;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
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.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.geometry.Bounds;
|
||||||
|
import javafx.scene.control.SkinBase;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单选按钮组皮肤
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-26
|
||||||
|
*/
|
||||||
|
public class RadioButtonGroupSkin extends SkinBase<RadioButtonGroup> {
|
||||||
|
|
||||||
|
/** 动画时长 */
|
||||||
|
private static final Duration SLIDER_DURATION = Duration.millis(320);
|
||||||
|
|
||||||
|
/** 按钮容器 */
|
||||||
|
private final HBox box;
|
||||||
|
|
||||||
|
/** 滑块 */
|
||||||
|
private final Region slider;
|
||||||
|
|
||||||
|
/** 滑块 x */
|
||||||
|
private final DoubleProperty sliderX;
|
||||||
|
|
||||||
|
/** 滑块 y */
|
||||||
|
private final DoubleProperty sliderY;
|
||||||
|
|
||||||
|
/** 滑块宽度 */
|
||||||
|
private final DoubleProperty sliderWidth;
|
||||||
|
|
||||||
|
/** 滑块高度 */
|
||||||
|
private final DoubleProperty sliderHeight;
|
||||||
|
|
||||||
|
/** 滑块动画 */
|
||||||
|
private Timeline sliderTimeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造按钮组皮肤
|
||||||
|
*
|
||||||
|
* @param control 按钮组控件
|
||||||
|
*/
|
||||||
|
public RadioButtonGroupSkin(RadioButtonGroup control) {
|
||||||
|
super(control);
|
||||||
|
|
||||||
|
sliderX = new SimpleDoubleProperty();
|
||||||
|
sliderY = new SimpleDoubleProperty();
|
||||||
|
sliderWidth = new SimpleDoubleProperty();
|
||||||
|
sliderHeight = new SimpleDoubleProperty();
|
||||||
|
sliderTimeline = new Timeline();
|
||||||
|
|
||||||
|
box = new HBox();
|
||||||
|
box.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_BOX);
|
||||||
|
|
||||||
|
slider = new Region();
|
||||||
|
slider.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_SLIDER);
|
||||||
|
slider.setManaged(false);
|
||||||
|
slider.setMouseTransparent(true);
|
||||||
|
|
||||||
|
sliderX.addListener((obs, o, n) -> applySliderBounds());
|
||||||
|
sliderY.addListener((obs, o, n) -> applySliderBounds());
|
||||||
|
sliderWidth.addListener((obs, o, n) -> applySliderBounds());
|
||||||
|
sliderHeight.addListener((obs, o, n) -> applySliderBounds());
|
||||||
|
|
||||||
|
box.alignmentProperty().bind(control.alignmentProperty());
|
||||||
|
box.spacingProperty().bind(Bindings.createDoubleBinding(
|
||||||
|
() -> control.getMode() == RadioButtonGroup.Mode.BUTTON && control.getSpacing() < 1 ? -1 : control.getSpacing(),
|
||||||
|
control.modeProperty(),
|
||||||
|
control.spacingProperty()
|
||||||
|
));
|
||||||
|
getChildren().add(new StackPane() {{
|
||||||
|
getStyleClass().add(RadioButtonGroup.STYLE_CLASS_BOX);
|
||||||
|
getChildren().addAll(slider, box);
|
||||||
|
}});
|
||||||
|
|
||||||
|
rebuildButtons();
|
||||||
|
initListeners(control);
|
||||||
|
updateMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化监听
|
||||||
|
*
|
||||||
|
* @param control 控件
|
||||||
|
*/
|
||||||
|
private void initListeners(RadioButtonGroup control) {
|
||||||
|
control.getButtons().addListener((ListChangeListener<ToggleButton>) change -> rebuildButtons());
|
||||||
|
control.selectedButtonProperty().addListener((obs, o, n) -> syncSlider());
|
||||||
|
control.modeProperty().addListener((obs, o, n) -> {
|
||||||
|
updateMode();
|
||||||
|
syncSlider();
|
||||||
|
});
|
||||||
|
box.layoutBoundsProperty().addListener((obs, o, n) -> {
|
||||||
|
syncSlider();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建按钮结构
|
||||||
|
*/
|
||||||
|
private void rebuildButtons() {
|
||||||
|
box.getChildren().setAll(getSkinnable().getButtons());
|
||||||
|
syncButtonStyleClass();
|
||||||
|
syncSlider();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步按钮样式
|
||||||
|
*/
|
||||||
|
private void syncButtonStyleClass() {
|
||||||
|
int size = getSkinnable().getButtons().size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
ToggleButton button = getSkinnable().getButtons().get(i);
|
||||||
|
button.getStyleClass().removeAll(
|
||||||
|
RadioButtonGroup.STYLE_CLASS_BUTTON,
|
||||||
|
RadioButtonGroup.STYLE_CLASS_FIRST,
|
||||||
|
RadioButtonGroup.STYLE_CLASS_MIDDLE,
|
||||||
|
RadioButtonGroup.STYLE_CLASS_LAST,
|
||||||
|
RadioButtonGroup.STYLE_CLASS_SINGLE
|
||||||
|
);
|
||||||
|
button.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_BUTTON);
|
||||||
|
button.selectedProperty().addListener((obs, o, n) -> button.setViewOrder(n ? -1 : 0));
|
||||||
|
button.setViewOrder(button.isSelected() ? -1 : 0);
|
||||||
|
button.layoutBoundsProperty().addListener((obs, o, n) -> syncSlider());
|
||||||
|
button.boundsInParentProperty().addListener((obs, o, n) -> syncSlider());
|
||||||
|
|
||||||
|
if (size == 1) {
|
||||||
|
button.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_SINGLE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
button.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_FIRST);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i == size - 1) {
|
||||||
|
button.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_LAST);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
button.getStyleClass().add(RadioButtonGroup.STYLE_CLASS_MIDDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用滑块位置和尺寸
|
||||||
|
*/
|
||||||
|
private void applySliderBounds() {
|
||||||
|
slider.resizeRelocate(sliderX.get(), sliderY.get(), sliderWidth.get(), sliderHeight.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新模式
|
||||||
|
*/
|
||||||
|
private void updateMode() {
|
||||||
|
boolean sliderMode = getSkinnable().getMode() == RadioButtonGroup.Mode.SLIDER;
|
||||||
|
slider.setVisible(sliderMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步滑块位置
|
||||||
|
*/
|
||||||
|
private void syncSlider() {
|
||||||
|
if (getSkinnable().getMode() != RadioButtonGroup.Mode.SLIDER) {
|
||||||
|
sliderTimeline.stop();
|
||||||
|
sliderX.set(0);
|
||||||
|
sliderY.set(0);
|
||||||
|
sliderWidth.set(0);
|
||||||
|
sliderHeight.set(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ToggleButton button = getSkinnable().getSelectedButton();
|
||||||
|
if (button == null || !box.getChildren().contains(button)) {
|
||||||
|
sliderTimeline.stop();
|
||||||
|
sliderX.set(0);
|
||||||
|
sliderY.set(0);
|
||||||
|
sliderWidth.set(0);
|
||||||
|
sliderHeight.set(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bounds bounds = button.getBoundsInParent();
|
||||||
|
double targetX = bounds.getMinX() + 2;
|
||||||
|
double targetWidth = Math.max(0, bounds.getWidth() - 4);
|
||||||
|
double targetHeight = Math.max(0, box.getHeight() - 4);
|
||||||
|
double targetY = 2;
|
||||||
|
|
||||||
|
if (sliderWidth.get() <= 0 || sliderHeight.get() <= 0) {
|
||||||
|
sliderTimeline.stop();
|
||||||
|
sliderX.set(targetX);
|
||||||
|
sliderY.set(targetY);
|
||||||
|
sliderWidth.set(targetWidth);
|
||||||
|
sliderHeight.set(targetHeight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sliderTimeline.stop();
|
||||||
|
sliderTimeline = new Timeline(
|
||||||
|
new KeyFrame(
|
||||||
|
SLIDER_DURATION,
|
||||||
|
new KeyValue(sliderX, targetX, Interpolates.EASE_OUT_EXPO.getValue()),
|
||||||
|
new KeyValue(sliderY, targetY, Interpolates.EASE_OUT_EXPO.getValue()),
|
||||||
|
new KeyValue(sliderWidth, targetWidth, Interpolates.EASE_OUT_EXPO.getValue()),
|
||||||
|
new KeyValue(sliderHeight, targetHeight, Interpolates.EASE_OUT_EXPO.getValue())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sliderTimeline.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,6 +102,11 @@ public class SelectableLabel extends TextArea implements TimiFXUI, TimiFXUI.Colo
|
|||||||
return defaultSkin;
|
return defaultSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return SelectableLabel.class.getResource(RESOURCE + "style/components/selectable-label.css").toExternalForm();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定文本样式
|
* 绑定文本样式
|
||||||
*
|
*
|
||||||
|
|||||||
+11
-34
@@ -1,20 +1,19 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.java.bean.CallbackArg;
|
import com.imyeyu.java.bean.CallbackArg;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
import javafx.animation.TranslateTransition;
|
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
import javafx.scene.control.TabPane;
|
|
||||||
import javafx.scene.control.skin.TabPaneSkin;
|
import javafx.scene.control.skin.TabPaneSkin;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.util.Duration;
|
import javafx.scene.shape.Rectangle;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -26,16 +25,11 @@ import java.util.List;
|
|||||||
* @since 2022-07-24 10:54
|
* @since 2022-07-24 10:54
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
public class TabPane extends javafx.scene.control.TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
||||||
|
|
||||||
/** 添加按钮 */
|
@Override
|
||||||
protected final IconButton add;
|
public String getUserAgentStylesheet() {
|
||||||
|
return TabPane.class.getResource(RESOURCE + "style/components/tab-pane.css").toExternalForm();
|
||||||
/** 默认构造 */
|
|
||||||
public XTabPane() {
|
|
||||||
add = new IconButton(TimiFXIcon.fromName("PLUS")).withBackground();
|
|
||||||
add.getStyleClass().add(CSS.BORDER_RB);
|
|
||||||
add.setPrefWidth(20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,24 +39,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
try {
|
try {
|
||||||
StackPane tabHeaderArea = Ref.getFieldValue(tabPaneSkin, "tabHeaderArea", StackPane.class);
|
StackPane tabHeaderArea = Ref.getFieldValue(tabPaneSkin, "tabHeaderArea", StackPane.class);
|
||||||
StackPane headersRegion = Ref.getFieldValue(tabHeaderArea, "headersRegion", StackPane.class);
|
StackPane headersRegion = Ref.getFieldValue(tabHeaderArea, "headersRegion", StackPane.class);
|
||||||
StackPane headersBackground = Ref.getFieldValue(tabHeaderArea, "headerBackground", StackPane.class);
|
Rectangle headerClip = Ref.getFieldValue(tabHeaderArea, "headerClip", Rectangle.class);
|
||||||
|
|
||||||
// 添加按钮
|
|
||||||
TranslateTransition transition = new TranslateTransition();
|
|
||||||
transition.setNode(add);
|
|
||||||
transition.setDuration(Duration.millis(150));
|
|
||||||
headersRegion.widthProperty().addListener((obs, oldWidth, newWidth) -> {
|
|
||||||
if (oldWidth.doubleValue() < newWidth.doubleValue()) {
|
|
||||||
transition.setFromX(add.getTranslateX());
|
|
||||||
transition.setToX(newWidth.intValue());
|
|
||||||
transition.play();
|
|
||||||
} else {
|
|
||||||
add.setTranslateX(newWidth.intValue());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add.prefHeightProperty().bind(headersBackground.heightProperty());
|
|
||||||
StackPane.setAlignment(add, Pos.CENTER_LEFT);
|
|
||||||
headersBackground.getChildren().add(add);
|
|
||||||
|
|
||||||
// 关闭按钮调整
|
// 关闭按钮调整
|
||||||
CallbackArg<Node> resizeCloseButton = tabHeaderSkin -> {
|
CallbackArg<Node> resizeCloseButton = tabHeaderSkin -> {
|
||||||
@@ -72,7 +49,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
closeBtn.setPrefWidth(18);
|
closeBtn.setPrefWidth(18);
|
||||||
closeBtn.getStyleClass().clear();
|
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.setAlignment(Pos.CENTER_LEFT);
|
||||||
icon.setMouseTransparent(true);
|
icon.setMouseTransparent(true);
|
||||||
icon.prefWidthProperty().bind(closeBtn.widthProperty());
|
icon.prefWidthProperty().bind(closeBtn.widthProperty());
|
||||||
@@ -82,7 +59,7 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
closeBtn.getChildren().add(icon);
|
closeBtn.getChildren().add(icon);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ObservableList<Node> tabList = headersRegion.getChildren();
|
ObservableList<Node> tabList = headersRegion.getChildren();
|
||||||
@@ -92,8 +69,8 @@ public class XTabPane extends TabPane implements TimiFXUI, TimiFXUI.Colorful {
|
|||||||
headersRegion.getChildren().addListener((ListChangeListener<Node>) c -> {
|
headersRegion.getChildren().addListener((ListChangeListener<Node>) c -> {
|
||||||
if (c.next()) {
|
if (c.next()) {
|
||||||
List<? extends Node> list = c.getAddedSubList();
|
List<? extends Node> list = c.getAddedSubList();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (Node node : list) {
|
||||||
resizeCloseButton.handler(list.get(i));
|
resizeCloseButton.handler(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.popup.PopupTipsService;
|
import com.imyeyu.fx.ui.components.popup.PopupTipsService;
|
||||||
import com.imyeyu.fx.utils.Anchor;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.layout.Layout;
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.Callback;
|
import com.imyeyu.java.bean.Callback;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
@@ -39,6 +40,7 @@ import javafx.scene.input.KeyCode;
|
|||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@@ -51,6 +53,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复杂文本域编辑器,显示按钮操作文本域,文本域显示行号,可自定义操作功能
|
* 复杂文本域编辑器,显示按钮操作文本域,文本域显示行号,可自定义操作功能
|
||||||
@@ -115,31 +118,36 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
showLineNumber = new SimpleBooleanProperty(true);
|
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();
|
||||||
|
undo.setBorder(Stroke.RIGHT);
|
||||||
undo.disableProperty().bind(undoableProperty().not());
|
undo.disableProperty().bind(undoableProperty().not());
|
||||||
PopupTipsService.installText(undo, TimiFXUI.MULTILINGUAL.text("undo"));
|
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();
|
||||||
|
redo.setBorder(Stroke.RIGHT);
|
||||||
redo.disableProperty().bind(redoableProperty().not());
|
redo.disableProperty().bind(redoableProperty().not());
|
||||||
PopupTipsService.installText(redo, TimiFXUI.MULTILINGUAL.text("redo"));
|
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();
|
||||||
|
copy.setBorder(Stroke.RIGHT);
|
||||||
PopupTipsService.installText(copy, TimiFXUI.MULTILINGUAL.text("copy"));
|
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();
|
||||||
|
cut.setBorder(Stroke.RIGHT);
|
||||||
cut.disableProperty().bind(editableProperty().not());
|
cut.disableProperty().bind(editableProperty().not());
|
||||||
PopupTipsService.installText(cut, TimiFXUI.MULTILINGUAL.text("cut"));
|
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();
|
||||||
|
paste.setBorder(Stroke.RIGHT);
|
||||||
paste.disableProperty().bind(editableProperty().not());
|
paste.disableProperty().bind(editableProperty().not());
|
||||||
PopupTipsService.installText(paste, TimiFXUI.MULTILINGUAL.text("paste"));
|
PopupTipsService.installText(paste, TimiFXUI.MULTILINGUAL.text("paste"));
|
||||||
|
|
||||||
// 换行
|
// 换行
|
||||||
wrap = new ToggleIcon(TimiFXIcon.fromName("WRAP"));
|
wrap = new ToggleIcon(TimiFXIcon.get(TimiIcon.WRAP));
|
||||||
wrap.setBorder(Stroke.RIGHT);
|
wrap.setBorder(Stroke.RIGHT);
|
||||||
PopupTipsService.installText(wrap, TimiFXUI.MULTILINGUAL.text("wrap"));
|
PopupTipsService.installText(wrap, TimiFXUI.MULTILINGUAL.text("wrap"));
|
||||||
|
|
||||||
@@ -153,12 +161,13 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
|
|
||||||
// 顶部背景(阻止触发文本域选择)
|
// 顶部背景(阻止触发文本域选择)
|
||||||
Button headerBackground = new Button(" ");
|
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);
|
headerBackground.setBackground(BG.DEFAULT);
|
||||||
|
|
||||||
AnchorPane headerPane = new AnchorPane();
|
AnchorPane headerPane = new AnchorPane();
|
||||||
Anchor.def(header);
|
Layout.anchor.fill(header);
|
||||||
Anchor.def(headerBackground);
|
Layout.anchor.fill(headerBackground);
|
||||||
headerPane.getChildren().setAll(headerBackground, header);
|
headerPane.getChildren().setAll(headerBackground, header);
|
||||||
headerPane.setBorder(Stroke.BOTTOM);
|
headerPane.setBorder(Stroke.BOTTOM);
|
||||||
|
|
||||||
@@ -258,6 +267,11 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Objects.requireNonNull(TextAreaEditor.class.getResource(RESOURCE + "style/components/text-area-editor.css")).toExternalForm();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Skin<?> createDefaultSkin() {
|
protected Skin<?> createDefaultSkin() {
|
||||||
TextAreaEditSkin skin = new TextAreaEditSkin(this);
|
TextAreaEditSkin skin = new TextAreaEditSkin(this);
|
||||||
@@ -315,7 +329,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 平滑滚动
|
// 平滑滚动
|
||||||
SmoothScroll.scrollPaneV(scrollPane);
|
SmoothScroll.pane.install(scrollPane);
|
||||||
|
|
||||||
root.setLeft(lineNumber);
|
root.setLeft(lineNumber);
|
||||||
root.setCenter(scrollPane);
|
root.setCenter(scrollPane);
|
||||||
@@ -406,7 +420,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
selects = FXCollections.observableHashMap();
|
selects = FXCollections.observableHashMap();
|
||||||
|
|
||||||
// 查找
|
// 查找
|
||||||
Text icon = TimiFXIcon.fromName("MAGNIFIER");
|
Text icon = TimiFXIcon.get(TimiIcon.MAGNIFIER);
|
||||||
keyword = new TextField() {
|
keyword = new TextField() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -420,7 +434,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
textGroup.setTranslateY(-.5);
|
textGroup.setTranslateY(-.5);
|
||||||
|
|
||||||
// 匹配大小写
|
// 匹配大小写
|
||||||
toggleCase = new ToggleIcon(TimiFXIcon.fromName("FONTSIZE"));
|
toggleCase = new ToggleIcon(TimiFXIcon.get(TimiIcon.FONT_SIZE));
|
||||||
toggleCase.setBorder(Stroke.LEFT);
|
toggleCase.setBorder(Stroke.LEFT);
|
||||||
toggleCase.setCursor(Cursor.DEFAULT);
|
toggleCase.setCursor(Cursor.DEFAULT);
|
||||||
toggleCase.setFocusTraversable(false);
|
toggleCase.setFocusTraversable(false);
|
||||||
@@ -440,29 +454,31 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
keyword.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
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 = TimiFXUI.label(" ");
|
||||||
result.setPadding(new Insets(0, 4, 0, 4));
|
result.setPadding(new Insets(0, 4, 0, 4));
|
||||||
IconButton prev = new IconButton(TimiFXIcon.fromName("ARROW_0_N")).withBackground();
|
IconButton prev = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_N)).withBackground();
|
||||||
prev.getStyleClass().add(CSS.BORDER_R);
|
prev.setBorder(Stroke.RIGHT);
|
||||||
prev.setFocusTraversable(false);
|
prev.setFocusTraversable(false);
|
||||||
IconButton next = new IconButton(TimiFXIcon.fromName("ARROW_0_S")).withBackground();
|
IconButton next = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_0_S)).withBackground();
|
||||||
next.getStyleClass().add(CSS.BORDER_R);
|
next.setBorder(Stroke.RIGHT);
|
||||||
next.setFocusTraversable(false);
|
next.setFocusTraversable(false);
|
||||||
|
|
||||||
// 关闭
|
// 关闭
|
||||||
IconButton close = new IconButton(TimiFXIcon.fromName("FAIL")).withBackground();
|
IconButton close = new IconButton(TimiFXIcon.get(TimiIcon.FAIL)).withBackground();
|
||||||
close.getStyleClass().add(CSS.BORDER_L);
|
close.setBorder(Stroke.LEFT);
|
||||||
close.setFocusTraversable(false);
|
close.setFocusTraversable(false);
|
||||||
|
|
||||||
// 替换值
|
// 替换值
|
||||||
TextField replaceValue = new TextField();
|
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());
|
replaceValue.disableProperty().bind(editableProperty().not());
|
||||||
Button replace = new Button(TimiFXUI.MULTILINGUAL.text("replace"));
|
Button replace = new Button(TimiFXUI.MULTILINGUAL.text("replace"));
|
||||||
replace.getStyleClass().add(CSS.BORDER_R);
|
replace.setBorder(Stroke.RIGHT);
|
||||||
replace.setFocusTraversable(false);
|
replace.setFocusTraversable(false);
|
||||||
replace.disableProperty().bind(editableProperty().not().or(replaceValue.textProperty().isEmpty().or(Bindings.isEmpty(selects))));
|
replace.disableProperty().bind(editableProperty().not().or(replaceValue.textProperty().isEmpty().or(Bindings.isEmpty(selects))));
|
||||||
replace.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
|
replace.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
|
||||||
@@ -471,12 +487,12 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
Button replaceAll = new Button(TimiFXUI.MULTILINGUAL.text("replace_all"));
|
Button replaceAll = new Button(TimiFXUI.MULTILINGUAL.text("replace_all"));
|
||||||
replaceAll.getStyleClass().add(CSS.BORDER_R);
|
replaceAll.setBorder(Stroke.RIGHT);
|
||||||
replaceAll.setFocusTraversable(false);
|
replaceAll.setFocusTraversable(false);
|
||||||
replaceAll.disableProperty().bind(replace.disabledProperty());
|
replaceAll.disableProperty().bind(replace.disabledProperty());
|
||||||
|
|
||||||
getStyleClass().add("find-pane");
|
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);
|
setBorder(Stroke.BOTTOM);
|
||||||
setBackground(BG.DEFAULT);
|
setBackground(BG.DEFAULT);
|
||||||
|
|
||||||
@@ -639,7 +655,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
// 不可单向绑定,TextArea 内部需要调度 setVvalue,也不可双向绑定,会造成滚动错位
|
// 不可单向绑定,TextArea 内部需要调度 setVvalue,也不可双向绑定,会造成滚动错位
|
||||||
scrollPane.setVvalue(newV.doubleValue());
|
scrollPane.setVvalue(newV.doubleValue());
|
||||||
});
|
});
|
||||||
getStyleClass().add(CSS.BORDER_L);
|
setBorder(Stroke.LEFT);
|
||||||
setEditable(false);
|
setEditable(false);
|
||||||
setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
|
setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
|
||||||
addEventFilter(MouseEvent.ANY, Event::consume);
|
addEventFilter(MouseEvent.ANY, Event::consume);
|
||||||
@@ -682,7 +698,7 @@ public class TextAreaEditor extends TextArea implements TimiFXUI {
|
|||||||
scrollPane.vvalueProperty().addListener((obs, o, n) -> scrollPane.setVvalue(ownerScrollPane.getVvalue()));
|
scrollPane.vvalueProperty().addListener((obs, o, n) -> scrollPane.setVvalue(ownerScrollPane.getVvalue()));
|
||||||
scrollPane.getContent().setCursor(Cursor.DEFAULT);
|
scrollPane.getContent().setCursor(Cursor.DEFAULT);
|
||||||
|
|
||||||
SmoothScroll.scrollPaneV(scrollPane);
|
SmoothScroll.pane.install(scrollPane);
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.Windows;
|
||||||
import com.imyeyu.java.bean.CallbackArg;
|
import com.imyeyu.java.bean.CallbackArg;
|
||||||
import com.imyeyu.java.ref.Ref;
|
import com.imyeyu.java.ref.Ref;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
@@ -71,8 +72,8 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
|
|||||||
textGroup.setTranslateY(-.5);
|
textGroup.setTranslateY(-.5);
|
||||||
|
|
||||||
// 插入编辑器图标
|
// 插入编辑器图标
|
||||||
IconButton editor = new IconButton(TimiFXIcon.fromName("WRITING")).withBackground();
|
IconButton editor = new IconButton(TimiFXIcon.get(TimiIcon.WRITING)).withBackground();
|
||||||
editor.getStyleClass().add(CSS.BORDER_L);
|
editor.setBorder(Stroke.LEFT);
|
||||||
editor.setCursor(Cursor.DEFAULT);
|
editor.setCursor(Cursor.DEFAULT);
|
||||||
|
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
@@ -88,7 +89,7 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
|
|||||||
if (onShowEditorEvent != null) {
|
if (onShowEditorEvent != null) {
|
||||||
onShowEditorEvent.handler(editorStage);
|
onShowEditorEvent.handler(editorStage);
|
||||||
}
|
}
|
||||||
TimiFX.showCenter(getScene().getWindow(), editorStage);
|
Windows.showCentered(getScene().getWindow(), editorStage);
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@@ -138,12 +139,12 @@ public class TextAreaEditorField extends TextField implements TimiFXUI {
|
|||||||
|
|
||||||
EditorStage() {
|
EditorStage() {
|
||||||
editor = new TextAreaEditor();
|
editor = new TextAreaEditor();
|
||||||
editor.getStyleClass().add(CSS.BORDER_T);
|
editor.setBorder(Stroke.TOP);
|
||||||
|
|
||||||
Scene scene = new Scene(editor);
|
Scene scene = new Scene(editor);
|
||||||
scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(scene);
|
||||||
setScene(scene);
|
setScene(scene);
|
||||||
getIcons().add(TimiFXIcon.iconFromName("WRITING"));
|
getIcons().add(TimiFXIcon.rerender(TimiIcon.WRITING));
|
||||||
setWidth(850);
|
setWidth(850);
|
||||||
setHeight(620);
|
setHeight(620);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import javafx.scene.text.TextFlow;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本流组件,支持插入超链文本,解析富文本:{@link #matcher(String)}
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-09-05 10:41
|
|
||||||
*/
|
|
||||||
public class TextFlower extends TextFlow implements TimiFXUI {
|
|
||||||
|
|
||||||
/** 默认构造器 */
|
|
||||||
public TextFlower() {
|
|
||||||
getStyleClass().add(CSS.MINECRAFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本开始,添加一个制表符
|
|
||||||
*
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textStart() {
|
|
||||||
getChildren().add(new Text("\t"));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,左侧补充一个制表符,通常是段落开始
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textStart(String text) {
|
|
||||||
getChildren().add(new Text("\t" + text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower text(String text) {
|
|
||||||
getChildren().add(new Text(text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,左侧补充空格
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textLSP(String text) {
|
|
||||||
getChildren().add(new Text(" " + text));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加文本,右侧补充空格
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower textRSP(String text) {
|
|
||||||
getChildren().add(new Text(text + " "));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接文本
|
|
||||||
*
|
|
||||||
* @param text 显示文本
|
|
||||||
* @param link 访问链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower link(String text, String link) {
|
|
||||||
getChildren().add(new XHyperlink(text, link));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接文本
|
|
||||||
*
|
|
||||||
* @param icon 图标
|
|
||||||
* @param text 显示文本
|
|
||||||
* @param link 访问链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower link(Node icon, String text, String link) {
|
|
||||||
getChildren().add(new XHyperlink(icon, text, link));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 追加链接,显示文本为链接
|
|
||||||
*
|
|
||||||
* @param value 内容
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower syncLink(String value) {
|
|
||||||
getChildren().add(new XHyperlink(value, value));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置最后一个文本节点为链接
|
|
||||||
*
|
|
||||||
* @param link 链接
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower asLink(String link) {
|
|
||||||
Node text = getChildren().removeLast();
|
|
||||||
if (text instanceof Text t) {
|
|
||||||
getChildren().add(new XHyperlink(t.getText(), link));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 富文本匹配解析字符串,转义使用 '\'
|
|
||||||
* <br>
|
|
||||||
* <p>格式标准:
|
|
||||||
* <ul>
|
|
||||||
* <li>超链:[可选文本,连接]</li>
|
|
||||||
* <li>图标:<可选颜色, timi-fx-icon 图标名称></li>
|
|
||||||
* <li>重点:`[可选样式,内容]`</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param value 字符串
|
|
||||||
* @return 本实例
|
|
||||||
*/
|
|
||||||
public TextFlower matcher(String value) {
|
|
||||||
if (TimiJava.isNotEmpty(value)) {
|
|
||||||
getChildren().addAll(RichMatcher.parse(value));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 富文本匹配
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:23
|
|
||||||
*/
|
|
||||||
private static class RichMatcher {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 匹配正则
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:58
|
|
||||||
*/
|
|
||||||
private enum Regex {
|
|
||||||
|
|
||||||
LINK("\\[(.*?)]"),
|
|
||||||
|
|
||||||
ICON("<(.*?)>"),
|
|
||||||
|
|
||||||
SPAN("`(.*?)`");
|
|
||||||
|
|
||||||
final Pattern pattern;
|
|
||||||
|
|
||||||
Regex(String regex) {
|
|
||||||
this.pattern = Pattern.compile(regex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重点内容样式
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-10-10 11:58
|
|
||||||
*/
|
|
||||||
private enum Style {
|
|
||||||
|
|
||||||
UNDERLINE("u", "underline");
|
|
||||||
|
|
||||||
private final String[] matches;
|
|
||||||
|
|
||||||
Style(String... matches) {
|
|
||||||
this.matches = matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Style fromMatcher(String matcher) {
|
|
||||||
Style[] values = values();
|
|
||||||
for (Style value : values) {
|
|
||||||
String[] matches = value.matches;
|
|
||||||
for (String match : matches) {
|
|
||||||
if (match.equalsIgnoreCase(matcher)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析富文本匹配
|
|
||||||
*
|
|
||||||
* @param data 文本内容
|
|
||||||
* @return 匹配节点列表
|
|
||||||
*/
|
|
||||||
static List<Node> parse(String data) {
|
|
||||||
List<Node> result = new ArrayList<>();
|
|
||||||
|
|
||||||
Regex[] regexes = Regex.values();
|
|
||||||
|
|
||||||
Map<String, Node> nodeMap = new HashMap<>();
|
|
||||||
|
|
||||||
int[] insertI = {0};
|
|
||||||
String value = data;
|
|
||||||
Matcher matcher;
|
|
||||||
for (int i = 0; i < regexes.length; i++) {
|
|
||||||
final int j = i;
|
|
||||||
matcher = regexes[i].pattern.matcher(value);
|
|
||||||
|
|
||||||
value = matcher.replaceAll(matchResult -> {
|
|
||||||
if (matchResult.start() - 1 != -1) {
|
|
||||||
if (data.charAt(matchResult.start() - 1) == '\\') {
|
|
||||||
return matchResult.group();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodeMap.put(String.valueOf(insertI[0]), node(regexes[j], value(regexes[j], matchResult.group())));
|
|
||||||
return "[" + insertI[0]++ + "]";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 二次解析
|
|
||||||
matcher = Pattern.compile("\\[(.*?)]").matcher(value);
|
|
||||||
int end = 0;
|
|
||||||
while (matcher.find()) {
|
|
||||||
if (matcher.start() - 1 != -1) {
|
|
||||||
if (data.charAt(matcher.start() - 1) == '\\') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (end != matcher.start()) {
|
|
||||||
result.add(new Text(value.substring(end, matcher.start())));
|
|
||||||
}
|
|
||||||
result.add(nodeMap.get(value(Regex.LINK, matcher.group())));
|
|
||||||
end = matcher.end();
|
|
||||||
}
|
|
||||||
result.add(new Text(value.substring(end)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析正则匹配值
|
|
||||||
*
|
|
||||||
* @param regex 匹配正则
|
|
||||||
* @param matcherResult 匹配结果
|
|
||||||
* @return 匹配值
|
|
||||||
*/
|
|
||||||
private static String value(Regex regex, String matcherResult) {
|
|
||||||
return switch (regex) {
|
|
||||||
case LINK, ICON, SPAN -> matcherResult.substring(1, matcherResult.length() - 1);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析节点
|
|
||||||
*
|
|
||||||
* @param regex 匹配正则
|
|
||||||
* @param value 匹配值
|
|
||||||
* @return 节点
|
|
||||||
*/
|
|
||||||
private static Node node(Regex regex, String value) {
|
|
||||||
return switch (regex) {
|
|
||||||
// 超链
|
|
||||||
case LINK -> {
|
|
||||||
int sp = value.indexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
yield new XHyperlink(value.trim());
|
|
||||||
} else {
|
|
||||||
while (value.charAt(sp - 1) == '\\') {
|
|
||||||
sp = value.indexOf(",", sp + 1);
|
|
||||||
}
|
|
||||||
yield new XHyperlink(value.substring(0, sp).trim(), value.substring(sp + 1).trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 图标
|
|
||||||
case ICON -> {
|
|
||||||
Text icon;
|
|
||||||
int sp = value.lastIndexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
icon = TimiFXIcon.fromName(value);
|
|
||||||
} else {
|
|
||||||
icon = TimiFXIcon.fromName(value.substring(sp + 1).trim());
|
|
||||||
icon.setFill(Paint.valueOf(value.substring(0, sp).trim()));
|
|
||||||
}
|
|
||||||
yield icon;
|
|
||||||
}
|
|
||||||
// 重点内容
|
|
||||||
case SPAN -> {
|
|
||||||
int sp = value.indexOf(",");
|
|
||||||
if (sp == -1) {
|
|
||||||
yield new Text(value);
|
|
||||||
} else {
|
|
||||||
Text text = new Text(value.substring(sp + 1).trim());
|
|
||||||
String[] styles = value.substring(0, sp).trim().split(" ");
|
|
||||||
for (String s : styles) {
|
|
||||||
Style style = Style.fromMatcher(s);
|
|
||||||
if (style == null) {
|
|
||||||
text.setFill(Paint.valueOf(s));
|
|
||||||
} else {
|
|
||||||
if (style == Style.UNDERLINE) {
|
|
||||||
text.setUnderline(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yield text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,9 @@ package com.imyeyu.fx.ui.components;
|
|||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
import com.imyeyu.fx.TimiFX;
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.Nodes;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
@@ -29,6 +31,9 @@ import java.time.LocalDateTime;
|
|||||||
public class TimePicker extends HBox implements TimiFXUI {
|
public class TimePicker extends HBox implements TimiFXUI {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "time-picker";
|
private static final String STYLE_CLASS = "time-picker";
|
||||||
|
private static final String STYLE_CLASS_POPUP = "time-picker-popup";
|
||||||
|
private static final String STYLE_CLASS_TIME_BOX = "time-picker-time-box";
|
||||||
|
private static final String STYLE_CLASS_NOW = "time-picker-now";
|
||||||
|
|
||||||
private final Popup popup;
|
private final Popup popup;
|
||||||
private final TextField textField;
|
private final TextField textField;
|
||||||
@@ -39,6 +44,8 @@ public class TimePicker extends HBox implements TimiFXUI {
|
|||||||
|
|
||||||
/** 默认构造器 */
|
/** 默认构造器 */
|
||||||
public TimePicker() {
|
public TimePicker() {
|
||||||
|
getStylesheets().add(TimePicker.class.getResource(RESOURCE + "style/components/time-picker.css").toExternalForm());
|
||||||
|
|
||||||
value = new SimpleIntegerProperty(-1);
|
value = new SimpleIntegerProperty(-1);
|
||||||
|
|
||||||
textField = new TextField();
|
textField = new TextField();
|
||||||
@@ -46,29 +53,31 @@ public class TimePicker extends HBox implements TimiFXUI {
|
|||||||
textField.setAlignment(Pos.CENTER);
|
textField.setAlignment(Pos.CENTER);
|
||||||
textField.setPrefWidth(70);
|
textField.setPrefWidth(70);
|
||||||
textField.setOnContextMenuRequested(Event::consume);
|
textField.setOnContextMenuRequested(Event::consume);
|
||||||
IconButton button = new IconButton(TimiFXIcon.fromName("CLOCK")).withBackground();
|
IconButton button = new IconButton(TimiFXIcon.get(TimiIcon.CLOCK)).withBackground();
|
||||||
button.getStyleClass().add(CSS.BORDER_TRB);
|
button.setBorder(Stroke.EX_LEFT);
|
||||||
|
|
||||||
// 时间选择
|
// 时间选择
|
||||||
hour = new ListView<>();
|
hour = new ListView<>();
|
||||||
minute = new ListView<>();
|
minute = new ListView<>();
|
||||||
second = new ListView<>();
|
second = new ListView<>();
|
||||||
|
|
||||||
hour.getStyleClass().add(CSS.BORDER_RB);
|
hour.setBorder(Stroke.RB);
|
||||||
minute.getStyleClass().add(CSS.BORDER_RB);
|
minute.setBorder(Stroke.RB);
|
||||||
second.getStyleClass().add(CSS.BORDER_B);
|
second.setBorder(Stroke.BOTTOM);
|
||||||
|
|
||||||
// 此刻
|
// 此刻
|
||||||
Button now = new Button(TimiFXUI.MULTILINGUAL.text("now"));
|
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);
|
||||||
|
timeBox.getStyleClass().add(STYLE_CLASS_TIME_BOX);
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
|
root.getStylesheets().add(TimePicker.class.getResource(RESOURCE + "style/components/time-picker.css").toExternalForm());
|
||||||
|
root.getStyleClass().add(STYLE_CLASS_POPUP);
|
||||||
BorderPane.setAlignment(now, Pos.CENTER_RIGHT);
|
BorderPane.setAlignment(now, Pos.CENTER_RIGHT);
|
||||||
root.setEffect(Shadow.POPUP);
|
|
||||||
root.setBorder(Stroke.DEFAULT);
|
|
||||||
root.setPrefSize(140, 211);
|
root.setPrefSize(140, 211);
|
||||||
root.setBackground(BG.DEFAULT);
|
root.setCenter(timeBox);
|
||||||
root.setCenter(new HBox(hour, minute, second));
|
|
||||||
root.setBottom(now);
|
root.setBottom(now);
|
||||||
|
|
||||||
popup = new Popup();
|
popup = new Popup();
|
||||||
@@ -127,9 +136,9 @@ public class TimePicker extends HBox implements TimiFXUI {
|
|||||||
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
minute.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
||||||
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
second.addEventFilter(ScrollEvent.SCROLL, middleScroll);
|
||||||
|
|
||||||
TimiFX.hoverFocus(hour);
|
Nodes.requestFocusOnHover(hour);
|
||||||
TimiFX.hoverFocus(minute);
|
Nodes.requestFocusOnHover(minute);
|
||||||
TimiFX.hoverFocus(second);
|
Nodes.requestFocusOnHover(second);
|
||||||
|
|
||||||
// 值监听
|
// 值监听
|
||||||
value.addListener((obs, o, n) -> {
|
value.addListener((obs, o, n) -> {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
package com.imyeyu.fx.ui.components;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
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 com.imyeyu.java.TimiJava;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
@@ -25,7 +25,7 @@ import javafx.scene.layout.Background;
|
|||||||
public class ToggleIcon extends ToggleButton implements TimiFXUI {
|
public class ToggleIcon extends ToggleButton implements TimiFXUI {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "toggle-icon";
|
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;
|
protected final Node selected;
|
||||||
@@ -118,7 +118,7 @@ public class ToggleIcon extends ToggleButton implements TimiFXUI {
|
|||||||
graphicProperty().bind(Bindings.when(selectedProperty()).then(selected).otherwise(otherwise));
|
graphicProperty().bind(Bindings.when(selectedProperty()).then(selected).otherwise(otherwise));
|
||||||
}
|
}
|
||||||
selected.getStyleClass().add("icon");
|
selected.getStyleClass().add("icon");
|
||||||
TimiFX.hoverOpacity(this);
|
Nodes.bindHoverOpacity(this);
|
||||||
|
|
||||||
getStyleClass().setAll(CSS.MINECRAFT, STYLE_CLASS);
|
getStyleClass().setAll(CSS.MINECRAFT, STYLE_CLASS);
|
||||||
setAlignment(Pos.CENTER);
|
setAlignment(Pos.CENTER);
|
||||||
@@ -139,6 +139,11 @@ public class ToggleIcon extends ToggleButton implements TimiFXUI {
|
|||||||
}, textProperty(), autoSize, skinProperty()));
|
}, textProperty(), autoSize, skinProperty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return ToggleIcon.class.getResource(RESOURCE + "style/components/toggle-icon.css").toExternalForm();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加按钮背景
|
* 添加按钮背景
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public final class TrayFX implements TimiFXUI {
|
|||||||
root = new StackPane();
|
root = new StackPane();
|
||||||
|
|
||||||
Scene scene = new Scene(root);
|
Scene scene = new Scene(root);
|
||||||
scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(scene, TrayFX.class.getResource(RESOURCE + "style/components/tray-menu.css").toExternalForm());
|
||||||
scene.setFill(null);
|
scene.setFill(null);
|
||||||
stage = new Stage();
|
stage = new Stage();
|
||||||
stage.setWidth(1);
|
stage.setWidth(1);
|
||||||
|
|||||||
+4
-5
@@ -1,9 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.components;
|
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.collections.ObservableList;
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.control.TreeView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不显示根节点的树形结构,实现多个根节点
|
* 不显示根节点的树形结构,实现多个根节点
|
||||||
@@ -11,17 +10,17 @@ import javafx.scene.control.TreeView;
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2021-04-26 01:34
|
* @since 2021-04-26 01:34
|
||||||
*/
|
*/
|
||||||
public class XTreeView<T> extends TreeView<T> {
|
public class TreeView<T> extends javafx.scene.control.TreeView<T> {
|
||||||
|
|
||||||
private final TreeItem<T> dummyRoot = new TreeItem<>();
|
private final TreeItem<T> dummyRoot = new TreeItem<>();
|
||||||
|
|
||||||
/** 默认构造 */
|
/** 默认构造 */
|
||||||
public XTreeView() {
|
public TreeView() {
|
||||||
dummyRoot.setExpanded(true);
|
dummyRoot.setExpanded(true);
|
||||||
setRoot(dummyRoot);
|
setRoot(dummyRoot);
|
||||||
setShowRoot(false);
|
setShowRoot(false);
|
||||||
// 平滑滚动
|
// 平滑滚动
|
||||||
SmoothScroll.virtual(this);
|
SmoothScroll.virtual.install(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.components.alert;
|
package com.imyeyu.fx.ui.components.alert;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
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.CallbackArg;
|
||||||
import com.imyeyu.java.bean.CallbackArgReturn;
|
import com.imyeyu.java.bean.CallbackArgReturn;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
@@ -102,7 +102,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Scene scene = new Scene(root);
|
Scene scene = new Scene(root);
|
||||||
scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(scene);
|
||||||
initModality(Modality.WINDOW_MODAL);
|
initModality(Modality.WINDOW_MODAL);
|
||||||
setScene(scene);
|
setScene(scene);
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
|
|||||||
initOwner(owner);
|
initOwner(owner);
|
||||||
}
|
}
|
||||||
setOnShown(e -> {
|
setOnShown(e -> {
|
||||||
TimiFX.relativeCenter(owner, this);
|
Windows.centerOnOwner(owner, this);
|
||||||
callShownListeners(e);
|
callShownListeners(e);
|
||||||
});
|
});
|
||||||
show();
|
show();
|
||||||
@@ -200,7 +200,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
|
|||||||
initOwner(owner);
|
initOwner(owner);
|
||||||
}
|
}
|
||||||
setOnShown(e -> {
|
setOnShown(e -> {
|
||||||
TimiFX.relativeCenter(owner, this);
|
Windows.centerOnOwner(owner, this);
|
||||||
callShownListeners(e);
|
callShownListeners(e);
|
||||||
});
|
});
|
||||||
showAndWait();
|
showAndWait();
|
||||||
@@ -208,7 +208,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
|
|||||||
|
|
||||||
/** 相对于主屏幕中间显示 */
|
/** 相对于主屏幕中间显示 */
|
||||||
public void showRelativeCenter4PrimaryScreen() {
|
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) {
|
public void showRelativeCenter4Screen(Screen screen) {
|
||||||
initModality(Modality.APPLICATION_MODAL);
|
initModality(Modality.APPLICATION_MODAL);
|
||||||
setOnShown(e -> {
|
setOnShown(e -> {
|
||||||
TimiFX.relativeCenter4Screen(screen, this);
|
Windows.centerOnScreen(this, screen);
|
||||||
callShownListeners(e);
|
callShownListeners(e);
|
||||||
});
|
});
|
||||||
show();
|
show();
|
||||||
@@ -227,7 +227,7 @@ public abstract class AbstractAlert extends Stage implements TimiFXUI, TimiFXUI.
|
|||||||
|
|
||||||
/** 相对于主屏幕中间显示并等待 */
|
/** 相对于主屏幕中间显示并等待 */
|
||||||
public void showAwaitRelativeCenter4PrimaryScreen() {
|
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) {
|
public void showAwaitRelativeCenter4Screen(Screen screen) {
|
||||||
initModality(Modality.APPLICATION_MODAL);
|
initModality(Modality.APPLICATION_MODAL);
|
||||||
setOnShown(e -> {
|
setOnShown(e -> {
|
||||||
TimiFX.relativeCenter4Screen(screen, this);
|
Windows.centerOnScreen(this, screen);
|
||||||
callShownListeners(e);
|
callShownListeners(e);
|
||||||
});
|
});
|
||||||
showAndWait();
|
showAndWait();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components.alert;
|
package com.imyeyu.fx.ui.components.alert;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.FileTreeView;
|
import com.imyeyu.fx.ui.components.FileTreeView;
|
||||||
import com.imyeyu.fx.ui.components.IconButton;
|
import com.imyeyu.fx.ui.components.IconButton;
|
||||||
@@ -18,6 +19,7 @@ import javafx.scene.control.TextField;
|
|||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
@@ -66,27 +68,23 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
|
|||||||
VBox header = new VBox();
|
VBox header = new VBox();
|
||||||
|
|
||||||
// 主页
|
// 主页
|
||||||
IconButton home = new IconButton(TimiFXIcon.fromName("HOME")).withBackground();
|
IconButton home = new IconButton(TimiFXIcon.get(TimiIcon.HOME));
|
||||||
home.getStyleClass().add(CSS.BORDER_R);
|
|
||||||
PopupTipsService.installText(home, TimiFXUI.MULTILINGUAL.text("home"));
|
PopupTipsService.installText(home, TimiFXUI.MULTILINGUAL.text("home"));
|
||||||
|
|
||||||
// 刷新
|
// 刷新
|
||||||
IconButton refresh = new IconButton(TimiFXIcon.fromName("REFRESH")).withBackground();
|
IconButton refresh = new IconButton(TimiFXIcon.get(TimiIcon.REFRESH));
|
||||||
refresh.getStyleClass().add(CSS.BORDER_R);
|
|
||||||
PopupTipsService.installText(refresh, TimiFXUI.MULTILINGUAL.text("refresh"));
|
PopupTipsService.installText(refresh, TimiFXUI.MULTILINGUAL.text("refresh"));
|
||||||
|
|
||||||
// 创建文件夹
|
// 创建文件夹
|
||||||
IconButton mkdir = new IconButton(TimiFXIcon.fromName("FOLDER_ADD")).withBackground();
|
IconButton mkdir = new IconButton(TimiFXIcon.get(TimiIcon.FOLDER_ADD));
|
||||||
mkdir.getStyleClass().add(CSS.BORDER_R);
|
|
||||||
PopupTipsService.installText(mkdir, TimiFXUI.MULTILINGUAL.text("file.mkdir"));
|
PopupTipsService.installText(mkdir, TimiFXUI.MULTILINGUAL.text("file.mkdir"));
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
IconButton destroy = new IconButton(TimiFXIcon.fromName("FAIL", Colorful.RED)).withBackground();
|
IconButton destroy = new IconButton(TimiFXIcon.get(TimiIcon.FAIL, Colorful.RED));
|
||||||
destroy.getStyleClass().add(CSS.BORDER_R);
|
|
||||||
PopupTipsService.installText(destroy, TimiFXUI.MULTILINGUAL.text("delete"));
|
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"));
|
PopupTipsService.installText(toggleHide, TimiFXUI.MULTILINGUAL.text("file.show_hide"));
|
||||||
|
|
||||||
BorderPane ctrl = new BorderPane();
|
BorderPane ctrl = new BorderPane();
|
||||||
@@ -99,9 +97,8 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
|
|||||||
|
|
||||||
// 绝对路径
|
// 绝对路径
|
||||||
absolutePath = new TextField();
|
absolutePath = new TextField();
|
||||||
absolutePath.getStyleClass().add(CSS.BORDER_N);
|
absolutePath.setBorder(Border.EMPTY);
|
||||||
IconButton absolutePathGo = new IconButton(TimiFXIcon.fromName("ARROW_2_E")).withBackground();
|
IconButton absolutePathGo = new IconButton(TimiFXIcon.get(TimiIcon.ARROW_2_E));
|
||||||
absolutePathGo.getStyleClass().add(CSS.BORDER_L);
|
|
||||||
{
|
{
|
||||||
if (mode == SelectionMode.SINGLE) {
|
if (mode == SelectionMode.SINGLE) {
|
||||||
PopupTipsLabel tips = PopupTipsService.installBindingText(absolutePath, absolutePath.textProperty());
|
PopupTipsLabel tips = PopupTipsService.installBindingText(absolutePath, absolutePath.textProperty());
|
||||||
@@ -128,10 +125,10 @@ public abstract class AbstractAlertFile extends AbstractAlert implements TimiFXU
|
|||||||
|
|
||||||
{
|
{
|
||||||
confirm = AlertButton.confirm();
|
confirm = AlertButton.confirm();
|
||||||
confirm.getStyleClass().add(CSS.BORDER_L);
|
confirm.setBorder(Stroke.LEFT);
|
||||||
|
|
||||||
cancel = AlertButton.cancel();
|
cancel = AlertButton.cancel();
|
||||||
cancel.getStyleClass().add(CSS.BORDER_L);
|
cancel.setBorder(Stroke.LEFT);
|
||||||
|
|
||||||
setRightButtons(confirm, cancel);
|
setRightButtons(confirm, cancel);
|
||||||
btnPane.setPadding(Insets.EMPTY);
|
btnPane.setPadding(Insets.EMPTY);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components.alert;
|
package com.imyeyu.fx.ui.components.alert;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.control.SelectionMode;
|
||||||
@@ -24,7 +25,7 @@ public class AlertFileBlendSelector extends AbstractAlertFile {
|
|||||||
// 确认
|
// 确认
|
||||||
confirm.disableProperty().bind(Bindings.isEmpty(tree.getSelectionModel().getSelectedItems()));
|
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"));
|
setTitle(TimiFXUI.MULTILINGUAL.text("file.tips.select_directory"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components.alert;
|
package com.imyeyu.fx.ui.components.alert;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.control.SelectionMode;
|
||||||
@@ -30,7 +31,7 @@ public class AlertFilePathSelector extends AbstractAlertFile {
|
|||||||
return item == null || item.getValue().isFile();
|
return item == null || item.getValue().isFile();
|
||||||
}, tree.getSelectionModel().selectedItemProperty()));
|
}, tree.getSelectionModel().selectedItemProperty()));
|
||||||
|
|
||||||
getIcons().setAll(TimiFXIcon.iconFromName("FOLDER"));
|
getIcons().setAll(TimiFXIcon.rerender(TimiIcon.FOLDER));
|
||||||
setTitle(TimiFXUI.MULTILINGUAL.text("file.tips.select_directory"));
|
setTitle(TimiFXUI.MULTILINGUAL.text("file.tips.select_directory"));
|
||||||
|
|
||||||
addItemFilter(File::isDirectory);
|
addItemFilter(File::isDirectory);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.components.alert;
|
package com.imyeyu.fx.ui.components.alert;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
@@ -44,7 +45,7 @@ public class AlertFileSelector extends AbstractAlertFile {
|
|||||||
return item == null || item.getValue().isDirectory();
|
return item == null || item.getValue().isDirectory();
|
||||||
}, tree.getSelectionModel().selectedItemProperty()));
|
}, tree.getSelectionModel().selectedItemProperty()));
|
||||||
|
|
||||||
getIcons().setAll(TimiFXIcon.iconFromName("FILE"));
|
getIcons().setAll(TimiFXIcon.rerender(TimiIcon.FILE));
|
||||||
setTitle(TimiFXUI.MULTILINGUAL.text("file.select"));
|
setTitle(TimiFXUI.MULTILINGUAL.text("file.select"));
|
||||||
|
|
||||||
addItemFilter(file -> {
|
addItemFilter(file -> {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package com.imyeyu.fx.ui.components.alert;
|
|||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
import com.imyeyu.fx.TimiFX;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
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 com.imyeyu.java.bean.CallbackArg;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
@@ -85,7 +86,7 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
|
|||||||
public AlertTextArea(AlertType type, String title, String content, String text, AlertButton... buttons) {
|
public AlertTextArea(AlertType type, String title, String content, String text, AlertButton... buttons) {
|
||||||
super(new TextArea(), type, title, content, text, buttons);
|
super(new TextArea(), type, title, content, text, buttons);
|
||||||
|
|
||||||
SmoothScroll.textarea(getInput());
|
SmoothScroll.text.install(getInput());
|
||||||
setResizable(true);
|
setResizable(true);
|
||||||
|
|
||||||
// 没有按钮监听
|
// 没有按钮监听
|
||||||
@@ -102,7 +103,7 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
|
|||||||
super.content.setPadding(isEmpty ? Insets.EMPTY : PADDING_CONTENT);
|
super.content.setPadding(isEmpty ? Insets.EMPTY : PADDING_CONTENT);
|
||||||
super.btnPane.setPadding(isEmpty ? Insets.EMPTY : PADDING_BUTTON);
|
super.btnPane.setPadding(isEmpty ? Insets.EMPTY : PADDING_BUTTON);
|
||||||
});
|
});
|
||||||
TimiFX.toggleStyleClass4Binding(input, emptyButton, CSS.BORDER_T, CSS.BORDER_ALL);
|
input.borderProperty().bind(Bindings.when(emptyButton).then(Stroke.TOP).otherwise(Stroke.DEFAULT));
|
||||||
root.borderProperty().bind(Bindings.when(tips.visibleProperty()).then(Stroke.TOP).otherwise(Border.EMPTY));
|
root.borderProperty().bind(Bindings.when(tips.visibleProperty()).then(Stroke.TOP).otherwise(Border.EMPTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
|
|||||||
AlertTextArea alert = new AlertTextArea(content);
|
AlertTextArea alert = new AlertTextArea(content);
|
||||||
alert.getInput().setEditable(false);
|
alert.getInput().setEditable(false);
|
||||||
alert.clearButton();
|
alert.clearButton();
|
||||||
TimiFX.showCenter(owner, alert);
|
Windows.showCentered(owner, alert);
|
||||||
return alert;
|
return alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ public class AlertTextArea extends AbstractAlertInput<TextArea> {
|
|||||||
alert.getInput().setPrefSize(750, 340);
|
alert.getInput().setPrefSize(750, 340);
|
||||||
alert.content.setPadding(Insets.EMPTY);
|
alert.content.setPadding(Insets.EMPTY);
|
||||||
alert.btnPane.setPadding(Insets.EMPTY);
|
alert.btnPane.setPadding(Insets.EMPTY);
|
||||||
TimiFX.showCenter(owner, alert);
|
Windows.showCentered(owner, alert);
|
||||||
return alert;
|
return alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,573 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.TimiFX;
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.control.TitledPane;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纵向导航组件,可实现多级折叠导航
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class Navigation extends ScrollPane implements TimiFXUI {
|
||||||
|
|
||||||
|
/** 默认缩进像素 */
|
||||||
|
static final double DEFAULT_INDENT_SIZE = 16;
|
||||||
|
|
||||||
|
/** 导航项原始标题属性 */
|
||||||
|
private static final String RAW_ITEM_TEXT = "RAW_ITEM_TEXT";
|
||||||
|
|
||||||
|
/** 导航项原始图标属性 */
|
||||||
|
private static final String RAW_ITEM_GRAPHIC = "RAW_ITEM_GRAPHIC";
|
||||||
|
|
||||||
|
/** 导航项图标同步锁属性 */
|
||||||
|
private static final String GRAPHIC_SYNCING = "GRAPHIC_SYNCING";
|
||||||
|
|
||||||
|
/** 导航项是否已初始化 */
|
||||||
|
private static final String INITIALIZED = "INITIALIZED";
|
||||||
|
|
||||||
|
/** 导航数据列表 */
|
||||||
|
@Getter
|
||||||
|
protected final ObservableList<Node> items;
|
||||||
|
|
||||||
|
/** 已选中监听 */
|
||||||
|
protected final ObjectProperty<ToggleButton> selectedItem;
|
||||||
|
|
||||||
|
/** 缩进像素 */
|
||||||
|
private final DoubleProperty indentSize;
|
||||||
|
|
||||||
|
/** 根容器 */
|
||||||
|
private final VBox contentBox;
|
||||||
|
|
||||||
|
/** 选择组 */
|
||||||
|
private final ToggleGroup toggleGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public Navigation() {
|
||||||
|
items = FXCollections.observableArrayList();
|
||||||
|
selectedItem = new SimpleObjectProperty<>();
|
||||||
|
indentSize = new SimpleDoubleProperty(DEFAULT_INDENT_SIZE);
|
||||||
|
contentBox = new VBox();
|
||||||
|
toggleGroup = new ToggleGroup();
|
||||||
|
|
||||||
|
initView();
|
||||||
|
initSelection();
|
||||||
|
initPropertyListener();
|
||||||
|
initItemsListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserAgentStylesheet() {
|
||||||
|
return Navigation.class.getResource(RESOURCE + "style/components/navigation.css").toExternalForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化视图
|
||||||
|
*/
|
||||||
|
private void initView() {
|
||||||
|
getStyleClass().addAll("navigation", "sp-border");
|
||||||
|
setMaxWidth(Double.MAX_VALUE);
|
||||||
|
setVbarPolicy(ScrollBarPolicy.NEVER);
|
||||||
|
setFitToWidth(true);
|
||||||
|
setContent(contentBox);
|
||||||
|
|
||||||
|
SmoothScroll.pane.install(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化选中同步
|
||||||
|
*/
|
||||||
|
private void initSelection() {
|
||||||
|
selectedItem.addListener((obs, o, newSelectedItem) -> {
|
||||||
|
if (newSelectedItem == null) {
|
||||||
|
toggleGroup.selectToggle(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (toggleGroup.getToggles().contains(newSelectedItem)) {
|
||||||
|
toggleGroup.selectToggle(newSelectedItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggleGroup.selectedToggleProperty().addListener((obs, o, toggle) -> {
|
||||||
|
if (toggle instanceof ToggleButton button) {
|
||||||
|
selectedItem.set(button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedItem.set(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化属性监听
|
||||||
|
*/
|
||||||
|
private void initPropertyListener() {
|
||||||
|
indentSize.addListener((obs, o, n) -> rebuild());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化导航数据监听
|
||||||
|
*/
|
||||||
|
private void initItemsListener() {
|
||||||
|
items.addListener(this::handleItemsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理导航数据变更
|
||||||
|
*
|
||||||
|
* @param change 变更内容
|
||||||
|
*/
|
||||||
|
private void handleItemsChanged(ListChangeListener.Change<? extends Node> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
for (Node node : change.getAddedSubList()) {
|
||||||
|
bindGroup(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change.wasRemoved()) {
|
||||||
|
for (Node node : change.getRemoved()) {
|
||||||
|
unbindGroup(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定导航组刷新回调
|
||||||
|
*
|
||||||
|
* @param node 子节点
|
||||||
|
*/
|
||||||
|
private void bindGroup(Node node) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::rebuild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑导航组刷新回调
|
||||||
|
*
|
||||||
|
* @param node 子节点
|
||||||
|
*/
|
||||||
|
private void unbindGroup(Node node) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建导航结构
|
||||||
|
*/
|
||||||
|
private void rebuild() {
|
||||||
|
contentBox.getChildren().clear();
|
||||||
|
toggleGroup.getToggles().clear();
|
||||||
|
|
||||||
|
for (Node node : items) {
|
||||||
|
Node attachedNode = buildNode(node, 0);
|
||||||
|
if (attachedNode != null) {
|
||||||
|
contentBox.getChildren().add(attachedNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshStandaloneItemStyle();
|
||||||
|
if (selectedItem.get() != null && !toggleGroup.getToggles().contains(selectedItem.get())) {
|
||||||
|
selectedItem.set(null);
|
||||||
|
}
|
||||||
|
if (selectedItem.get() != null) {
|
||||||
|
toggleGroup.selectToggle(selectedItem.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建节点
|
||||||
|
*
|
||||||
|
* @param node 节点
|
||||||
|
* @param level 层级
|
||||||
|
* @return 可挂载节点
|
||||||
|
*/
|
||||||
|
private Node buildNode(Node node, int level) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
return buildGroup(group, level);
|
||||||
|
}
|
||||||
|
if (node instanceof ToggleButton button) {
|
||||||
|
return buildItem(button, level);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param level 层级
|
||||||
|
* @return 导航组节点
|
||||||
|
*/
|
||||||
|
private NavigationGroup buildGroup(NavigationGroup group, int level) {
|
||||||
|
int currentLevel = level + group.getLevelOffset();
|
||||||
|
group.applyLevel(currentLevel, getIndentSize());
|
||||||
|
if (!group.getStyleClass().contains("group-pane")) {
|
||||||
|
group.getStyleClass().add("group-pane");
|
||||||
|
}
|
||||||
|
|
||||||
|
VBox groupContent = group.getContentBox();
|
||||||
|
groupContent.getChildren().clear();
|
||||||
|
for (Node child : group.getItems()) {
|
||||||
|
Node childNode = buildNode(child, currentLevel + 1);
|
||||||
|
if (childNode != null) {
|
||||||
|
groupContent.getChildren().add(childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param level 层级
|
||||||
|
* @return 导航项节点
|
||||||
|
*/
|
||||||
|
private ToggleButton buildItem(ToggleButton button, int level) {
|
||||||
|
configureButton(button, level);
|
||||||
|
toggleGroup.getToggles().add(button);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新独立导航项样式
|
||||||
|
*/
|
||||||
|
private void refreshStandaloneItemStyle() {
|
||||||
|
List<Node> children = contentBox.getChildren();
|
||||||
|
for (int i = 0; i < children.size(); i++) {
|
||||||
|
Node node = children.get(i);
|
||||||
|
if (node instanceof ToggleButton button) {
|
||||||
|
button.getStyleClass().remove("after-group");
|
||||||
|
if (0 < i && children.get(i - 1) instanceof TitledPane) {
|
||||||
|
button.getStyleClass().add("after-group");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param level 层级
|
||||||
|
*/
|
||||||
|
private void configureButton(ToggleButton button, int level) {
|
||||||
|
cacheItemState(button);
|
||||||
|
button.setText(resolveItemText(button));
|
||||||
|
button.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
button.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
applyButtonIndent(button, Math.max(0, level) * getIndentSize());
|
||||||
|
button.getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
|
||||||
|
|
||||||
|
if (!Boolean.TRUE.equals(button.getProperties().get(INITIALIZED))) {
|
||||||
|
button.addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
|
||||||
|
button.graphicProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!Boolean.TRUE.equals(button.getProperties().get(GRAPHIC_SYNCING))) {
|
||||||
|
button.getProperties().put(RAW_ITEM_GRAPHIC, n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
button.getProperties().put(INITIALIZED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存导航项原始状态
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
*/
|
||||||
|
private void cacheItemState(ToggleButton button) {
|
||||||
|
if (!(button.getProperties().get(RAW_ITEM_TEXT) instanceof String)) {
|
||||||
|
button.getProperties().put(RAW_ITEM_TEXT, button.getText());
|
||||||
|
}
|
||||||
|
if (!button.getProperties().containsKey(RAW_ITEM_GRAPHIC)) {
|
||||||
|
button.getProperties().put(RAW_ITEM_GRAPHIC, button.getGraphic());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导航项原始标题
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @return 原始标题
|
||||||
|
*/
|
||||||
|
private String resolveItemText(ToggleButton button) {
|
||||||
|
cacheItemState(button);
|
||||||
|
return (String) button.getProperties().get(RAW_ITEM_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用导航项缩进
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
* @param indentWidth 缩进宽度
|
||||||
|
*/
|
||||||
|
private void applyButtonIndent(ToggleButton button, double indentWidth) {
|
||||||
|
Node rawGraphic = (Node) button.getProperties().get(RAW_ITEM_GRAPHIC);
|
||||||
|
if (0 == indentWidth) {
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, true);
|
||||||
|
button.setGraphic(rawGraphic);
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region spacer = new Region();
|
||||||
|
spacer.setMinWidth(indentWidth);
|
||||||
|
spacer.setPrefWidth(indentWidth);
|
||||||
|
spacer.setMaxWidth(indentWidth);
|
||||||
|
|
||||||
|
HBox graphicBox = new HBox();
|
||||||
|
graphicBox.getChildren().add(spacer);
|
||||||
|
if (rawGraphic != null) {
|
||||||
|
graphicBox.getChildren().add(rawGraphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, true);
|
||||||
|
button.setGraphic(graphicBox);
|
||||||
|
button.getProperties().put(GRAPHIC_SYNCING, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航按钮
|
||||||
|
*
|
||||||
|
* @param buttons 导航按钮
|
||||||
|
*/
|
||||||
|
public void add(ToggleButton... buttons) {
|
||||||
|
getItems().addAll(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param groups 导航组
|
||||||
|
*/
|
||||||
|
public void add(NavigationGroup... groups) {
|
||||||
|
getItems().addAll(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航节点
|
||||||
|
*
|
||||||
|
* @param nodes 导航节点
|
||||||
|
*/
|
||||||
|
public void add(Node... nodes) {
|
||||||
|
getItems().addAll(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认没有展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, 0, false, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addExpandedGroup(String title, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, 0, true, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认没有展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, int level, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, level, false, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加默认展开的导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addExpandedGroup(String title, int level, ToggleButton... buttons) {
|
||||||
|
return addGroup(title, level, true, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 构造的导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(String title, int level, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
NavigationGroup group = new NavigationGroup(title).levelOffset(level).expanded(isExpanded);
|
||||||
|
group.add(buttons);
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group) {
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
return addGroup(group, group.getLevelOffset(), isExpanded, buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param group 导航组
|
||||||
|
* @param level 缩进偏移量
|
||||||
|
* @param isExpanded true 为默认展开
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 原导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup addGroup(NavigationGroup group, int level, boolean isExpanded, ToggleButton... buttons) {
|
||||||
|
group.levelOffset(level).expanded(isExpanded).add(buttons);
|
||||||
|
add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该按钮所属组
|
||||||
|
*
|
||||||
|
* @param button 按钮
|
||||||
|
* @return 所属组,null 时为不属于任何组
|
||||||
|
*/
|
||||||
|
public NavigationGroup getGroup(ToggleButton button) {
|
||||||
|
for (Node node : items) {
|
||||||
|
NavigationGroup group = findGroup(node, button);
|
||||||
|
if (group != null) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前激活导航项
|
||||||
|
*
|
||||||
|
* @param button 导航项
|
||||||
|
*/
|
||||||
|
public void setSelectedItem(ToggleButton button) {
|
||||||
|
selectedItem.set(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前激活的导航项
|
||||||
|
*
|
||||||
|
* @return 当前激活的导航项
|
||||||
|
*/
|
||||||
|
public ToggleButton getSelectedItem() {
|
||||||
|
return selectedItem.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取激活导航项监听
|
||||||
|
*
|
||||||
|
* @return 激活导航项监听
|
||||||
|
*/
|
||||||
|
public ObjectProperty<ToggleButton> selectedItem() {
|
||||||
|
return selectedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缩进像素
|
||||||
|
*
|
||||||
|
* @param indentSize 缩进像素
|
||||||
|
*/
|
||||||
|
public void setIndentSize(double indentSize) {
|
||||||
|
this.indentSize.set(Math.max(0, indentSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缩进像素
|
||||||
|
*
|
||||||
|
* @return 缩进像素
|
||||||
|
*/
|
||||||
|
public double getIndentSize() {
|
||||||
|
return indentSize.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缩进像素属性
|
||||||
|
*
|
||||||
|
* @return 缩进像素属性
|
||||||
|
*/
|
||||||
|
public DoubleProperty indentSize() {
|
||||||
|
return indentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找按钮所属导航组
|
||||||
|
*
|
||||||
|
* @param node 当前节点
|
||||||
|
* @param button 目标按钮
|
||||||
|
* @return 所属导航组
|
||||||
|
*/
|
||||||
|
private NavigationGroup findGroup(Node node, ToggleButton button) {
|
||||||
|
if (!(node instanceof NavigationGroup group)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Node child : group.getItems()) {
|
||||||
|
if (child == button) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
NavigationGroup nestedGroup = findGroup(child, button);
|
||||||
|
if (nestedGroup != null) {
|
||||||
|
return nestedGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.TitledPane;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航组
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class NavigationGroup extends TitledPane {
|
||||||
|
|
||||||
|
/** 子节点列表 */
|
||||||
|
@Getter
|
||||||
|
private final ObservableList<Node> items;
|
||||||
|
|
||||||
|
/** 内容容器 */
|
||||||
|
private final VBox contentBox;
|
||||||
|
|
||||||
|
/** 结构变更回调 */
|
||||||
|
private Runnable structureChangedAction;
|
||||||
|
|
||||||
|
/** 原始标题 */
|
||||||
|
private String rawTitle;
|
||||||
|
|
||||||
|
/** 原始图标 */
|
||||||
|
private Node rawGraphic;
|
||||||
|
|
||||||
|
/** 标题同步锁 */
|
||||||
|
private boolean textSyncing;
|
||||||
|
|
||||||
|
/** 图标同步锁 */
|
||||||
|
private boolean graphicSyncing;
|
||||||
|
|
||||||
|
/** 标题缩进偏移量 */
|
||||||
|
private int levelOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public NavigationGroup() {
|
||||||
|
items = FXCollections.observableArrayList();
|
||||||
|
contentBox = new VBox();
|
||||||
|
structureChangedAction = () -> {};
|
||||||
|
rawTitle = "";
|
||||||
|
|
||||||
|
getStylesheets().add(NavigationGroup.class.getResource("/timifx/style/components/navigation.css").toExternalForm());
|
||||||
|
contentBox.setPadding(Insets.EMPTY);
|
||||||
|
setContent(contentBox);
|
||||||
|
getStyleClass().add("group-pane");
|
||||||
|
items.addListener(this::handleItemsChanged);
|
||||||
|
initRawStateListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过标题创建导航组
|
||||||
|
*
|
||||||
|
* @param title 标题
|
||||||
|
*/
|
||||||
|
public NavigationGroup(String title) {
|
||||||
|
this();
|
||||||
|
setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航项
|
||||||
|
*
|
||||||
|
* @param buttons 导航项
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(ToggleButton... buttons) {
|
||||||
|
items.addAll(buttons);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加导航组
|
||||||
|
*
|
||||||
|
* @param groups 导航组
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(NavigationGroup... groups) {
|
||||||
|
items.addAll(groups);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加子节点
|
||||||
|
*
|
||||||
|
* @param nodes 子节点
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup add(Node... nodes) {
|
||||||
|
items.addAll(nodes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否默认展开
|
||||||
|
*
|
||||||
|
* @param expanded true 为默认展开
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup expanded(boolean expanded) {
|
||||||
|
setExpanded(expanded);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置标题缩进偏移量
|
||||||
|
*
|
||||||
|
* @param levelOffset 偏移量
|
||||||
|
* @return 当前导航组
|
||||||
|
*/
|
||||||
|
public NavigationGroup levelOffset(int levelOffset) {
|
||||||
|
this.levelOffset = Math.max(0, levelOffset);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取内容容器
|
||||||
|
*
|
||||||
|
* @return 内容容器
|
||||||
|
*/
|
||||||
|
VBox getContentBox() {
|
||||||
|
return contentBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取标题缩进偏移量
|
||||||
|
*
|
||||||
|
* @return 标题缩进偏移量
|
||||||
|
*/
|
||||||
|
int getLevelOffset() {
|
||||||
|
return levelOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置结构变更回调
|
||||||
|
*
|
||||||
|
* @param structureChangedAction 回调
|
||||||
|
*/
|
||||||
|
void setStructureChangedAction(Runnable structureChangedAction) {
|
||||||
|
this.structureChangedAction = structureChangedAction == null ? () -> {} : structureChangedAction;
|
||||||
|
for (Node node : items) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::notifyStructureChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用显示层级
|
||||||
|
*
|
||||||
|
* @param level 层级
|
||||||
|
* @param indentSize 缩进像素
|
||||||
|
*/
|
||||||
|
void applyLevel(int level, double indentSize) {
|
||||||
|
textSyncing = true;
|
||||||
|
super.setText(rawTitle);
|
||||||
|
textSyncing = false;
|
||||||
|
applyGraphicIndent(Math.max(0, level) * indentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理子节点变更
|
||||||
|
*
|
||||||
|
* @param change 变更内容
|
||||||
|
*/
|
||||||
|
private void handleItemsChanged(ListChangeListener.Change<? extends Node> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
for (Node node : change.getAddedSubList()) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(this::notifyStructureChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change.wasRemoved()) {
|
||||||
|
for (Node node : change.getRemoved()) {
|
||||||
|
if (node instanceof NavigationGroup group) {
|
||||||
|
group.setStructureChangedAction(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyStructureChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发结构变更通知
|
||||||
|
*/
|
||||||
|
private void notifyStructureChanged() {
|
||||||
|
structureChangedAction.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化原始状态监听
|
||||||
|
*/
|
||||||
|
private void initRawStateListener() {
|
||||||
|
rawTitle = getText() == null ? "" : getText();
|
||||||
|
rawGraphic = getGraphic();
|
||||||
|
|
||||||
|
textProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!textSyncing) {
|
||||||
|
rawTitle = n == null ? "" : n;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
graphicProperty().addListener((obs, o, n) -> {
|
||||||
|
if (!graphicSyncing) {
|
||||||
|
rawGraphic = n;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用标题缩进
|
||||||
|
*
|
||||||
|
* @param indentWidth 缩进宽度
|
||||||
|
*/
|
||||||
|
private void applyGraphicIndent(double indentWidth) {
|
||||||
|
if (0 == indentWidth) {
|
||||||
|
graphicSyncing = true;
|
||||||
|
super.setGraphic(rawGraphic);
|
||||||
|
graphicSyncing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region spacer = new Region();
|
||||||
|
spacer.setMinWidth(indentWidth);
|
||||||
|
spacer.setPrefWidth(indentWidth);
|
||||||
|
spacer.setMaxWidth(indentWidth);
|
||||||
|
|
||||||
|
HBox graphicBox = new HBox();
|
||||||
|
graphicBox.getChildren().add(spacer);
|
||||||
|
if (rawGraphic != null) {
|
||||||
|
graphicBox.getChildren().add(rawGraphic);
|
||||||
|
}
|
||||||
|
graphicSyncing = true;
|
||||||
|
super.setGraphic(graphicBox);
|
||||||
|
graphicSyncing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
|
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航项
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-16
|
||||||
|
*/
|
||||||
|
public class NavigationItem extends ToggleButton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造器
|
||||||
|
*/
|
||||||
|
public NavigationItem() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过标题创建导航项
|
||||||
|
*
|
||||||
|
* @param text 标题
|
||||||
|
*/
|
||||||
|
public NavigationItem(String text) {
|
||||||
|
super(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/** 导航组件 */
|
||||||
|
package com.imyeyu.fx.ui.components.navigation;
|
||||||
@@ -3,6 +3,7 @@ package com.imyeyu.fx.ui.components.table;
|
|||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格可编辑单元格,相对原始的可编辑效果,此单元格没有输入框的样式,就像 Excel 那样
|
* 表格可编辑单元格,相对原始的可编辑效果,此单元格没有输入框的样式,就像 Excel 那样
|
||||||
@@ -27,7 +28,7 @@ public abstract class TextFieldTableCell<S> extends BindingTableCell<S, String,
|
|||||||
@Override
|
@Override
|
||||||
protected final TextField component() {
|
protected final TextField component() {
|
||||||
TextField textField = new TextField();
|
TextField textField = new TextField();
|
||||||
textField.getStyleClass().add(CSS.BORDER_N);
|
textField.setBorder(Border.EMPTY);
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* *
|
||||||
|
* Pixel Size to Font Size *
|
||||||
|
* *
|
||||||
|
* 1px: 0.083333em *
|
||||||
|
* 2px: 0.166667em *
|
||||||
|
* 3px: 0.25em *
|
||||||
|
* 4px: 0.333333em *
|
||||||
|
* 5px: 0.416667em *
|
||||||
|
* 6px: 0.5em *
|
||||||
|
* 7px: 0.583333em *
|
||||||
|
* 8px: 0.666667em *
|
||||||
|
* 9px: 0.75em *
|
||||||
|
* 10px: 0.833333em *
|
||||||
|
* 11px: 0.916667em *
|
||||||
|
* 12px: 1.0em *
|
||||||
|
* *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
- TimiFX 的样式表 -
|
||||||
|
|
||||||
|
1. 主体颜色为灰色,辅助色为靛青 #177CB0
|
||||||
|
2. style.css 仅保留导入入口
|
||||||
|
3. 基础控件、布局、工具类、组件样式分文件维护
|
||||||
|
|
||||||
|
*/
|
||||||
|
* {
|
||||||
|
-fx-tab-size: 4;
|
||||||
|
-fx-font-smoothing-type: gray;
|
||||||
|
}
|
||||||
|
.root {
|
||||||
|
-timi-fx-white-color: #FFF;
|
||||||
|
-timi-fx-red-color: #F30;
|
||||||
|
-timi-fx-brown-color: #A67D7B;
|
||||||
|
-timi-fx-black-color: #000;
|
||||||
|
-timi-fx-orange-color: #F60;
|
||||||
|
-timi-fx-yellow-color: #FF0;
|
||||||
|
-timi-fx-green-color: #393;
|
||||||
|
-timi-fx-dark-green-color: #373;
|
||||||
|
-timi-fx-gray-color: #666;
|
||||||
|
-timi-fx-blue-color: #008DCB;
|
||||||
|
-timi-fx-light-blue-color: #DDEAF0;
|
||||||
|
-timi-fx-gray-white-color: #F4F4F4;
|
||||||
|
-timi-fx-light-gray-color: #B5B5B5;
|
||||||
|
-timi-fx-dark-gray-color: #333;
|
||||||
|
-timi-fx-pink-color: #FF7A9B;
|
||||||
|
-timi-fx-transparent: transparent;
|
||||||
|
-timi-fx-focused-default-color: #177CB0;
|
||||||
|
-timi-fx-focused-light-color: #55B0DF;
|
||||||
|
-timi-fx-focused-dark-color: #0B6C9E;
|
||||||
|
-timi-fx-icon-disabled-color: #939393;
|
||||||
|
|
||||||
|
-timi-fx-color: -timi-fx-focused-default-color;
|
||||||
|
-timi-fx-icon-color: -timi-fx-dark-gray-color;
|
||||||
|
-timi-fx-border-color: -timi-fx-light-gray-color;
|
||||||
|
-timi-fx-popup-shadow: dropshadow(three-pass-box, rgba(0, 0, 0, .3), 5, 0, 0, 1);
|
||||||
|
-timi-fx-opacity-hover: .7;
|
||||||
|
-timi-fx-selected-color: #7CC4FF;
|
||||||
|
-timi-fx-opacity-disabled: .4;
|
||||||
|
|
||||||
|
-fx-accent: -timi-fx-color;
|
||||||
|
-fx-focus-color: transparent;
|
||||||
|
-fx-focused-base: transparent;
|
||||||
|
-fx-text-box-border: -timi-fx-border-color;
|
||||||
|
-fx-faint-focus-color: transparent;
|
||||||
|
-fx-shadow-highlight-color: transparent;
|
||||||
|
-fx-cell-focus-inner-border: transparent;
|
||||||
|
-fx-control-inner-background: -timi-fx-white-color;
|
||||||
|
}
|
||||||
|
/* --------------------------- 聚焦边距 --------------------------- */
|
||||||
|
.text-area:focused,
|
||||||
|
.text-field:focused {
|
||||||
|
-fx-background-insets: 1, 2;
|
||||||
|
}
|
||||||
|
.list-view:focused {
|
||||||
|
-fx-background-insets: 0, 0, 2;
|
||||||
|
}
|
||||||
|
.table-view:focused {
|
||||||
|
-fx-background-insets: 0, 0, 1;
|
||||||
|
}
|
||||||
|
/* --------------------------- 只读 --------------------------- */
|
||||||
|
.text-area:readonly,
|
||||||
|
.text-field:readonly {
|
||||||
|
-fx-text-fill: -timi-fx-gray-color;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
.date-time-picker {
|
||||||
|
-fx-pref-width: 200;
|
||||||
|
}
|
||||||
|
.date-time-picker-time-pane {
|
||||||
|
-fx-border-width: 0 0 0 1;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
-fx-background-color: -timi-fx-gray-white-color;
|
||||||
|
-fx-translate-y: -1;
|
||||||
|
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, .25), 4, 0, 0, 1);
|
||||||
|
}
|
||||||
|
.date-time-picker-time-box {
|
||||||
|
-fx-hgap: 0;
|
||||||
|
}
|
||||||
|
.date-time-picker-now {
|
||||||
|
-fx-alignment: center-right;
|
||||||
|
}
|
||||||
|
.date-time-picker-clear {
|
||||||
|
-fx-background-color: -timi-fx-gray-white-color;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.filled-slider .track {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.filled-slider .progress-bar .bar {
|
||||||
|
-fx-pref-height: 6;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
}
|
||||||
|
.filled-slider .thumb,
|
||||||
|
.filled-slider:focused .thumb {
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.x-hyperlink {
|
||||||
|
-fx-text-fill: -timi-fx-focused-default-color;
|
||||||
|
}
|
||||||
|
.x-hyperlink:hover {
|
||||||
|
-fx-underline: true;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.icon-button {
|
||||||
|
-fx-border-width: 1;
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.label-progress-bar .bar {
|
||||||
|
-fx-background-color: #7ACAF4;
|
||||||
|
}
|
||||||
|
.label-progress-bar:indeterminate .bar {
|
||||||
|
-fx-background-color: linear-gradient(to left, transparent, #7ACAF4);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
.navigation {
|
||||||
|
-fx-border-width: 1;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.navigation .navigation-button {
|
||||||
|
-fx-padding: .25em .833333em; /* 3 10 */
|
||||||
|
-fx-border-width: 0;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.navigation .navigation-button.after-group {
|
||||||
|
-fx-border-width: 1 0 0 0;
|
||||||
|
}
|
||||||
|
.navigation .navigation-button:hover {
|
||||||
|
-fx-background-color: #CCC;
|
||||||
|
}
|
||||||
|
.navigation .navigation-button:selected {
|
||||||
|
-fx-text-fill: -timi-fx-white-color;
|
||||||
|
-fx-background-color: -timi-fx-color;
|
||||||
|
}
|
||||||
|
.navigation .navigation-button:disabled {
|
||||||
|
-fx-opacity: -timi-fx-opacity-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-pane {
|
||||||
|
-fx-animated: false;
|
||||||
|
-fx-border-width: 1 0 0 0;
|
||||||
|
}
|
||||||
|
.group-pane.bottom-line {
|
||||||
|
-fx-border-width: 1 0 1 0;
|
||||||
|
}
|
||||||
|
.group-pane .content {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.button,
|
||||||
|
.toggle-button {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-pref-width: 28;
|
||||||
|
-fx-pref-height: 26;
|
||||||
|
-fx-background-insets: 0 !important;
|
||||||
|
-fx-background-radius: 0 !important;
|
||||||
|
}
|
||||||
|
.toggle-button:selected {
|
||||||
|
-fx-background-color: -timi-fx-selected-color !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
.radio-button-group .radio-button-group-box {
|
||||||
|
-fx-spacing: 0;
|
||||||
|
-fx-alignment: center-left;
|
||||||
|
}
|
||||||
|
.radio-button-group .radio-button-group-button {
|
||||||
|
-fx-padding: .25em .833333em;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-border-insets: 0;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-border-radius: 0;
|
||||||
|
-fx-border-style: solid;
|
||||||
|
-fx-border-width: 1;
|
||||||
|
}
|
||||||
|
.radio-button-group.button-mode .radio-button-group-button {
|
||||||
|
-fx-background-color: -timi-fx-white-color;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
-fx-text-fill: -timi-fx-dark-gray-color;
|
||||||
|
}
|
||||||
|
.radio-button-group.button-mode .radio-button-group-button:hover {
|
||||||
|
-fx-background-color: -timi-fx-gray-white-color;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
-fx-text-fill: -timi-fx-dark-gray-color;
|
||||||
|
}
|
||||||
|
.radio-button-group.button-mode .radio-button-group-button:selected,
|
||||||
|
.radio-button-group.button-mode .radio-button-group-button:selected:hover {
|
||||||
|
-fx-background-color: -timi-fx-color;
|
||||||
|
-fx-border-color: -timi-fx-color;
|
||||||
|
-fx-text-fill: -timi-fx-white-color;
|
||||||
|
}
|
||||||
|
.radio-button-group.slider-mode {
|
||||||
|
-fx-background-color: -timi-fx-light-gray-color;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
}
|
||||||
|
.radio-button-group.slider-mode .radio-button-group-button,
|
||||||
|
.radio-button-group.slider-mode .radio-button-group-button:hover,
|
||||||
|
.radio-button-group.slider-mode .radio-button-group-button:selected,
|
||||||
|
.radio-button-group.slider-mode .radio-button-group-button:selected:hover {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-border-color: transparent;
|
||||||
|
-fx-border-style: solid;
|
||||||
|
-fx-border-width: 1;
|
||||||
|
-fx-text-fill: -timi-fx-dark-gray-color;
|
||||||
|
}
|
||||||
|
.radio-button-group .radio-button-group-slider {
|
||||||
|
-fx-background-color: -timi-fx-white-color;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
-fx-border-radius: 0;
|
||||||
|
-fx-effect: null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.selectable-label * {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
.selectable-label .scroll-pane {
|
||||||
|
-fx-hbar-policy: never;
|
||||||
|
-fx-vbar-policy: never;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
.tab-pane {
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .headers-region > .tab {
|
||||||
|
-fx-padding: 0 0 0 .5em;
|
||||||
|
-fx-background-insets: 0 0 1 0, 0 1 1 0, 1 2 1 1;
|
||||||
|
-fx-background-radius: 0, 0, 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .headers-region > .tab:selected {
|
||||||
|
-fx-background-insets: 0 1 0 0, 0 1 0 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .headers-region > .tab > .tab-container > .tab-label {
|
||||||
|
-fx-padding: 0 .5em 0 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container > .tab-down-button {
|
||||||
|
-fx-padding: 0 .5em;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-background-radius: 0;
|
||||||
|
}
|
||||||
|
.tab-pane > .tab-header-area > .control-buttons-tab > .container > .tab-down-button > .arrow {
|
||||||
|
-fx-shape: "M301.5,393.5v1h1v1h1v1h1v1h1v1h1v-1h1v-1h1v-1h1v-1h1v-1Z";
|
||||||
|
-fx-min-width: 9;
|
||||||
|
-fx-min-height: 5;
|
||||||
|
-fx-pref-width: 9;
|
||||||
|
-fx-pref-height: 5;
|
||||||
|
}
|
||||||
|
.tab-pane:top > .tab-header-area {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.text-area-editor .find-field {
|
||||||
|
-fx-background-color: -timi-fx-white-color;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
}
|
||||||
|
.text-area-editor .replace-field {
|
||||||
|
-fx-padding: .25em .333333em .25em 1.25em; /* 3 4 3 15 */
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
.time-picker .text-field:readonly {
|
||||||
|
-fx-text-fill: -timi-fx-gray-color;
|
||||||
|
}
|
||||||
|
.time-picker-popup {
|
||||||
|
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, .3), 5, 0, 0, 1);
|
||||||
|
-fx-border-width: 1;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
-fx-background-color: -timi-fx-gray-white-color;
|
||||||
|
}
|
||||||
|
.time-picker-time-box {
|
||||||
|
-fx-spacing: 0;
|
||||||
|
}
|
||||||
|
.time-picker-now {
|
||||||
|
-fx-alignment: center-right;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.toggle-icon:disabled {
|
||||||
|
-fx-opacity: -timi-fx-opacity-disabled;
|
||||||
|
}
|
||||||
|
.toggle-icon:disabled .icon {
|
||||||
|
-fx-opacity: -timi-fx-opacity-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.tray-menu {
|
||||||
|
-fx-border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
+9
-397
@@ -1,81 +1,4 @@
|
|||||||
/******************************************************************************
|
|
||||||
* *
|
|
||||||
* Pixel Size to Font Size *
|
|
||||||
* *
|
|
||||||
* 1px: 0.083333em *
|
|
||||||
* 2px: 0.166667em *
|
|
||||||
* 3px: 0.25em *
|
|
||||||
* 4px: 0.333333em *
|
|
||||||
* 5px: 0.416667em *
|
|
||||||
* 6px: 0.5em *
|
|
||||||
* 7px: 0.583333em *
|
|
||||||
* 8px: 0.666667em *
|
|
||||||
* 9px: 0.75em *
|
|
||||||
* 10px: 0.833333em *
|
|
||||||
* 11px: 0.916667em *
|
|
||||||
* 12px: 1.0em *
|
|
||||||
* *
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
- TimiFX 的样式表 -
|
|
||||||
|
|
||||||
1. 主体颜色为灰色,辅助色为靛青 #177CB0
|
|
||||||
2. 基本组件在前,复杂组件在后,公共类最后
|
|
||||||
|
|
||||||
*/
|
|
||||||
* {
|
|
||||||
-fx-tab-size: 4;
|
|
||||||
-fx-font-smoothing-type: gray;
|
|
||||||
}
|
|
||||||
.root {
|
|
||||||
-timi-fx-color: #177CB0;
|
|
||||||
-timi-fx-icon-color: #333;
|
|
||||||
-timi-fx-border-color: #B5B5B5;
|
|
||||||
-timi-fx-popup-shadow: dropshadow(three-pass-box, rgba(0, 0, 0, .3), 5, 0, 0, 1);
|
|
||||||
-timi-fx-opacity-hover: .7;
|
|
||||||
-timi-fx-selected-color: #7CC4FF;
|
|
||||||
-timi-fx-opacity-disabled: .4;
|
|
||||||
|
|
||||||
-fx-accent: -timi-fx-color;
|
|
||||||
-fx-focus-color: transparent;
|
|
||||||
-fx-focused-base: transparent;
|
|
||||||
-fx-text-box-border: -timi-fx-border-color;
|
|
||||||
-fx-faint-focus-color: transparent;
|
|
||||||
-fx-shadow-highlight-color: transparent;
|
|
||||||
-fx-cell-focus-inner-border: transparent;
|
|
||||||
-fx-control-inner-background: #FFF;
|
|
||||||
}
|
|
||||||
/* --------------------------- 聚焦边距 --------------------------- */
|
|
||||||
.text-area:focused,
|
|
||||||
.text-field:focused {
|
|
||||||
-fx-background-insets: 1, 2;
|
|
||||||
}
|
|
||||||
.button:focused {
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
.list-view:focused {
|
|
||||||
-fx-background-insets: 0, 0, 2;
|
|
||||||
}
|
|
||||||
.table-view:focused {
|
|
||||||
-fx-background-insets: 0, 0, 1;
|
|
||||||
}
|
|
||||||
/* --------------------------- 只读 --------------------------- */
|
|
||||||
.text-area:readonly,
|
|
||||||
.text-field:readonly,
|
|
||||||
.time-picker:readonly {
|
|
||||||
-fx-text-fill: #666;
|
|
||||||
}
|
|
||||||
/* --------------------------- 控件 --------------------------- */
|
/* --------------------------- 控件 --------------------------- */
|
||||||
/* 可选标签 */
|
|
||||||
.selectable-label * {
|
|
||||||
-fx-background-color: transparent;
|
|
||||||
}
|
|
||||||
.selectable-label .scroll-pane {
|
|
||||||
-fx-hbar-policy: never;
|
|
||||||
-fx-vbar-policy: never;
|
|
||||||
}
|
|
||||||
/* 按钮 */
|
|
||||||
.button {
|
.button {
|
||||||
-fx-padding: .25em .833333em; /* 3 10 */
|
-fx-padding: .25em .833333em; /* 3 10 */
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -86,6 +9,7 @@
|
|||||||
}
|
}
|
||||||
.toggle-button {
|
.toggle-button {
|
||||||
-fx-padding: .25em .833333em; /* 3 10 */
|
-fx-padding: .25em .833333em; /* 3 10 */
|
||||||
|
-fx-pref-height: 26;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
@@ -95,19 +19,6 @@
|
|||||||
.toggle-button:selected {
|
.toggle-button:selected {
|
||||||
-fx-background-color: -timi-fx-selected-color;
|
-fx-background-color: -timi-fx-selected-color;
|
||||||
}
|
}
|
||||||
/* 图标按钮 */
|
|
||||||
.icon-button {
|
|
||||||
-fx-border-width: 1;
|
|
||||||
-fx-border-color: transparent;
|
|
||||||
}
|
|
||||||
/* 切换图标按钮 */
|
|
||||||
.toggle-icon:disabled {
|
|
||||||
-fx-opacity: -timi-fx-opacity-disabled;
|
|
||||||
}
|
|
||||||
.toggle-icon:disabled .icon {
|
|
||||||
-fx-opacity: -timi-fx-opacity-disabled;
|
|
||||||
}
|
|
||||||
/* 文本框 */
|
|
||||||
.text-field {
|
.text-field {
|
||||||
-fx-padding: .25em .333333em; /* 3 4 */
|
-fx-padding: .25em .333333em; /* 3 4 */
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -116,7 +27,6 @@
|
|||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
}
|
}
|
||||||
/* 文本域 */
|
|
||||||
.text-area {
|
.text-area {
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
@@ -133,15 +43,6 @@
|
|||||||
.text-area .scroll-pane {
|
.text-area .scroll-pane {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
/* 文本域编辑器 */
|
|
||||||
.text-area-editor .find-field {
|
|
||||||
-fx-background-color: #FFF;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
.text-area-editor .replace-field {
|
|
||||||
-fx-padding: .25em .333333em .25em 1.25em; /* 3 4 3 15 */
|
|
||||||
}
|
|
||||||
/* 滑动选择 */
|
|
||||||
.slider > .track {
|
.slider > .track {
|
||||||
-fx-padding: .25em;
|
-fx-padding: .25em;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
@@ -155,8 +56,8 @@
|
|||||||
.slider:focused > .thumb {
|
.slider:focused > .thumb {
|
||||||
-fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
|
-fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
|
||||||
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
|
||||||
|
-fx-background-radius: 0;
|
||||||
}
|
}
|
||||||
/* 树形结构 */
|
|
||||||
.tree-view {
|
.tree-view {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
@@ -171,7 +72,6 @@
|
|||||||
-fx-pref-width: 5;
|
-fx-pref-width: 5;
|
||||||
-fx-pref-height: 9;
|
-fx-pref-height: 9;
|
||||||
}
|
}
|
||||||
/* 列表 */
|
|
||||||
.list-view {
|
.list-view {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -183,7 +83,6 @@
|
|||||||
-fx-background-color: -fx-control-inner-background;
|
-fx-background-color: -fx-control-inner-background;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
}
|
}
|
||||||
/* 表格 */
|
|
||||||
.table-view {
|
.table-view {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -205,9 +104,7 @@
|
|||||||
.table-view .text-field:focused {
|
.table-view .text-field:focused {
|
||||||
-fx-background-insets: 1;
|
-fx-background-insets: 1;
|
||||||
}
|
}
|
||||||
/* 下拉选择,菜单按钮,颜色选择,日期选择 */
|
|
||||||
.combo-box,
|
.combo-box,
|
||||||
.menu-button,
|
|
||||||
.date-picker,
|
.date-picker,
|
||||||
.color-picker {
|
.color-picker {
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -219,7 +116,7 @@
|
|||||||
.combo-box .text-input,
|
.combo-box .text-input,
|
||||||
.date-picker .text-input {
|
.date-picker .text-input {
|
||||||
-fx-padding: 4;
|
-fx-padding: 4;
|
||||||
-fx-background-color: -fx-text-box-border, #FFF;
|
-fx-background-color: -fx-text-box-border, -timi-fx-white-color;
|
||||||
-fx-background-insets: 0, 0 1 0 0;
|
-fx-background-insets: 0, 0 1 0 0;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
}
|
}
|
||||||
@@ -232,7 +129,6 @@
|
|||||||
.menu-button.empty > .label {
|
.menu-button.empty > .label {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
/* 下拉箭头 */
|
|
||||||
.combo-box-base .text-field {
|
.combo-box-base .text-field {
|
||||||
-fx-border-width: 0;
|
-fx-border-width: 0;
|
||||||
}
|
}
|
||||||
@@ -256,7 +152,7 @@
|
|||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-translate-y: -1;
|
-fx-translate-y: -1;
|
||||||
-fx-border-width: 1 1 0 1;
|
-fx-border-width: 1 1 0 1;
|
||||||
-fx-background-color: -timi-fx-border-color, #FFF;
|
-fx-background-color: -timi-fx-border-color, -timi-fx-white-color;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
}
|
}
|
||||||
.combo-box .combo-box-popup .list-view .list-cell {
|
.combo-box .combo-box-popup .list-view .list-cell {
|
||||||
@@ -264,12 +160,12 @@
|
|||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
.combo-box .combo-box-popup .list-view .list-cell:filled:hover {
|
.combo-box .combo-box-popup .list-view .list-cell:filled:hover {
|
||||||
-fx-text-fill: #FFF;
|
-fx-text-fill: -timi-fx-white-color;
|
||||||
-fx-background-color: -timi-fx-color;
|
-fx-background-color: -timi-fx-color;
|
||||||
}
|
}
|
||||||
.combo-box .combo-box-popup .list-view .list-cell:filled:selected,
|
.combo-box .combo-box-popup .list-view .list-cell:filled:selected,
|
||||||
.combo-box .combo-box-popup .list-view .list-cell:filled:selected:hover {
|
.combo-box .combo-box-popup .list-view .list-cell:filled:selected:hover {
|
||||||
-fx-text-fill: #FFF;
|
-fx-text-fill: -timi-fx-white-color;
|
||||||
-fx-background-color: -timi-fx-color;
|
-fx-background-color: -timi-fx-color;
|
||||||
}
|
}
|
||||||
.combo-box .combo-box-popup .list-view .scroll-bar:vertical {
|
.combo-box .combo-box-popup .list-view .scroll-bar:vertical {
|
||||||
@@ -277,7 +173,6 @@
|
|||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: -fx-background;
|
-fx-background-color: -fx-background;
|
||||||
}
|
}
|
||||||
/* 单选,多选 */
|
|
||||||
.check-box,
|
.check-box,
|
||||||
.radio-button,
|
.radio-button,
|
||||||
.check-box:hover,
|
.check-box:hover,
|
||||||
@@ -302,30 +197,24 @@
|
|||||||
-fx-pref-width: 10;
|
-fx-pref-width: 10;
|
||||||
-fx-pref-height: 8;
|
-fx-pref-height: 8;
|
||||||
}
|
}
|
||||||
/* 弹出菜单 */
|
|
||||||
.context-menu {
|
.context-menu {
|
||||||
-fx-color: -fx-base;
|
-fx-color: -fx-base;
|
||||||
-fx-effect: -timi-fx-popup-shadow;
|
-fx-effect: -timi-fx-popup-shadow;
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: #FFF;
|
-fx-background-color: -timi-fx-white-color;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item:focused {
|
.context-menu .menu-item:focused {
|
||||||
-fx-background-color: -timi-fx-selected-color;
|
-fx-background-color: -timi-fx-selected-color;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item:focused .label {
|
.context-menu .menu-item:focused .label {
|
||||||
-fx-text-fill: #333;
|
-fx-text-fill: -timi-fx-dark-gray-color;
|
||||||
}
|
}
|
||||||
.context-menu .separator {
|
.context-menu .separator {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
/* 托盘菜单 */
|
|
||||||
.tray-menu {
|
|
||||||
-fx-border-width: 0;
|
|
||||||
}
|
|
||||||
/* 菜单 */
|
|
||||||
.menu > .right-container > .arrow {
|
.menu > .right-container > .arrow {
|
||||||
-fx-shape: "M303.5,391.5h1v1h1v1h1v1h1v1h1v1h-1v1h-1v1h-1v1h-1v1h-1Z";
|
-fx-shape: "M303.5,391.5h1v1h1v1h1v1h1v1h1v1h-1v1h-1v1h-1v1h-1v1h-1Z";
|
||||||
-fx-min-width: 5;
|
-fx-min-width: 5;
|
||||||
@@ -339,7 +228,6 @@
|
|||||||
.check-menu-item:checked > .left-container > .check {
|
.check-menu-item:checked > .left-container > .check {
|
||||||
-fx-shape: "M3,7v2h1v1h1v1h1v1h1v-1h1v-1h1V9h1V8h1V7h1V6h1V4h-2v1h-1v1H9v1H8v1H7v1H6V8H5V7H3z";
|
-fx-shape: "M3,7v2h1v1h1v1h1v1h1v-1h1v-1h1V9h1V8h1V7h1V6h1V4h-2v1h-1v1H9v1H8v1H7v1H6V8H5V7H3z";
|
||||||
}
|
}
|
||||||
/* 日期选择 */
|
|
||||||
.date-picker:focused {
|
.date-picker:focused {
|
||||||
-fx-background-color: -fx-control-inner-background;
|
-fx-background-color: -fx-control-inner-background;
|
||||||
}
|
}
|
||||||
@@ -386,7 +274,6 @@
|
|||||||
.date-picker-popup > * > .spinner > .button > .right-arrow {
|
.date-picker-popup > * > .spinner > .button > .right-arrow {
|
||||||
-fx-shape: "M306,394h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-2v1h1v1h1v1h1v1h1v1h1v1h1v1h-1v1h-1v1h-1v1h-1v1h-1v1h-1v1h2v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1Z";
|
-fx-shape: "M306,394h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-2v1h1v1h1v1h1v1h1v1h1v1h1v1h-1v1h-1v1h-1v1h-1v1h-1v1h-1v1h2v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1Z";
|
||||||
}
|
}
|
||||||
/* 颜色选择器 */
|
|
||||||
.color-palette {
|
.color-palette {
|
||||||
-fx-translate-y: -1;
|
-fx-translate-y: -1;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
@@ -411,7 +298,6 @@
|
|||||||
-fx-background-insets: 12px 0 0 0, 13px 1px 1px 1px;
|
-fx-background-insets: 12px 0 0 0, 13px 1px 1px 1px;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
}
|
}
|
||||||
/* 滚动条 */
|
|
||||||
.scroll-bar {
|
.scroll-bar {
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
}
|
}
|
||||||
@@ -442,7 +328,6 @@
|
|||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
}
|
}
|
||||||
/* 列表滚动条 */
|
|
||||||
.tree-view .scroll-bar:vertical,
|
.tree-view .scroll-bar:vertical,
|
||||||
.list-view .scroll-bar:vertical,
|
.list-view .scroll-bar:vertical,
|
||||||
.table-view .scroll-bar:vertical {
|
.table-view .scroll-bar:vertical {
|
||||||
@@ -450,7 +335,6 @@
|
|||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: -fx-background;
|
-fx-background-color: -fx-background;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-view .scroll-bar:horizontal,
|
.tree-view .scroll-bar:horizontal,
|
||||||
.list-view .scroll-bar:horizontal,
|
.list-view .scroll-bar:horizontal,
|
||||||
.table-view .scroll-bar:horizontal {
|
.table-view .scroll-bar:horizontal {
|
||||||
@@ -458,7 +342,6 @@
|
|||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: -fx-background;
|
-fx-background-color: -fx-background;
|
||||||
}
|
}
|
||||||
/* 进度条 */
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
-fx-padding: 1;
|
-fx-padding: 1;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -480,29 +363,6 @@
|
|||||||
.progress-bar:indeterminate .bar {
|
.progress-bar:indeterminate .bar {
|
||||||
-fx-background-color: linear-gradient(to left, transparent, -timi-fx-color);
|
-fx-background-color: linear-gradient(to left, transparent, -timi-fx-color);
|
||||||
}
|
}
|
||||||
/* 标签进度 */
|
|
||||||
.label-progress-bar .bar {
|
|
||||||
-fx-background-color: #7ACAF4;
|
|
||||||
}
|
|
||||||
.label-progress-bar:indeterminate .bar {
|
|
||||||
-fx-background-color: linear-gradient(to left, transparent, #7ACAF4);
|
|
||||||
}
|
|
||||||
/* 滑动选择 - 进度 */
|
|
||||||
.progress-slider .track {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
.progress-slider .progress-bar .bar {
|
|
||||||
-fx-pref-height: 6;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
/* 分页 */
|
|
||||||
.x-pagination .button,
|
|
||||||
.x-pagination .toggle-button {
|
|
||||||
-fx-padding: 0;
|
|
||||||
-fx-pref-width: 28;
|
|
||||||
-fx-pref-height: 26;
|
|
||||||
}
|
|
||||||
/* 标题组件 */
|
|
||||||
.titled-pane {
|
.titled-pane {
|
||||||
-fx-animate: false;
|
-fx-animate: false;
|
||||||
-fx-border-width: 1;
|
-fx-border-width: 1;
|
||||||
@@ -533,14 +393,13 @@
|
|||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-border-width: 2 0 0 0;
|
-fx-border-width: 2 0 0 0;
|
||||||
-fx-border-color: -timi-fx-border-color;
|
-fx-border-color: -timi-fx-border-color;
|
||||||
-fx-background-color: #FFF;
|
-fx-background-color: -timi-fx-white-color;
|
||||||
-fx-background-insets: 0;
|
-fx-background-insets: 0;
|
||||||
}
|
}
|
||||||
.titled-group .titled-pane {
|
.titled-group .titled-pane {
|
||||||
-fx-border-width: 0 0 1 0;
|
-fx-border-width: 0 0 1 0;
|
||||||
-fx-background-insets: 0, 0;
|
-fx-background-insets: 0, 0;
|
||||||
}
|
}
|
||||||
/* 图表 */
|
|
||||||
.chart {
|
.chart {
|
||||||
-fx-padding: 0 0 6 0;
|
-fx-padding: 0 0 6 0;
|
||||||
}
|
}
|
||||||
@@ -556,84 +415,6 @@
|
|||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
-fx-background-insets: 0, 6;
|
-fx-background-insets: 0, 6;
|
||||||
}
|
}
|
||||||
/* 导航 */
|
|
||||||
.navigation {
|
|
||||||
-fx-border-width: 1;
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
.navigation .group-pane {
|
|
||||||
-fx-animated: false;
|
|
||||||
-fx-border-width: 1 0 0 0;
|
|
||||||
}
|
|
||||||
.navigation .group-pane.bottom-line {
|
|
||||||
-fx-border-width: 1 0 1 0;
|
|
||||||
}
|
|
||||||
.navigation .group-pane .content {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
.navigation .navigation-button {
|
|
||||||
-fx-padding: .25em .833333em; /* 3 10 */
|
|
||||||
-fx-border-width: 0;
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
.navigation .navigation-button.after-group { /* 紧挨着上一个导航组时,添加上边框 */
|
|
||||||
-fx-border-width: 1 0 0 0;
|
|
||||||
}
|
|
||||||
.navigation .navigation-button:hover {
|
|
||||||
-fx-background-color: #CCC;
|
|
||||||
}
|
|
||||||
.navigation .navigation-button:selected {
|
|
||||||
-fx-text-fill: #FFF;
|
|
||||||
-fx-background-color: -timi-fx-color;
|
|
||||||
}
|
|
||||||
.navigation .navigation-button:disabled {
|
|
||||||
-fx-opacity: -timi-fx-opacity-disabled;
|
|
||||||
}
|
|
||||||
/* 可编辑表格 */
|
|
||||||
.editable-table .table-row-cell:odd {
|
|
||||||
-fx-background-color: -fx-table-cell-border-color, -fx-control-inner-background;
|
|
||||||
}
|
|
||||||
.editable-table .table-row-cell:filled:selected,
|
|
||||||
.editable-table .table-row-cell:filled:selected:focused {
|
|
||||||
-fx-padding: 0;
|
|
||||||
-fx-text-fill: -fx-selection-bar-text;
|
|
||||||
-fx-background: -timi-fx-selected-color;
|
|
||||||
-fx-border-width: 0;
|
|
||||||
-fx-background-color: -timi-fx-selected-color;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
-fx-table-cell-border-color: -timi-fx-selected-color;
|
|
||||||
}
|
|
||||||
.editable-table .table-cell {
|
|
||||||
-fx-padding: 0;
|
|
||||||
-fx-cell-size: 0;
|
|
||||||
-fx-border-width: .083333em .083333em .083333em 0; /* 1 1 1 0 */
|
|
||||||
}
|
|
||||||
.editable-table .table-row-cell .text-field {
|
|
||||||
-fx-background-color: -timi-fx-color, #FFF;
|
|
||||||
-fx-background-insets: 0, 0;
|
|
||||||
}
|
|
||||||
.editable-table .table-row-cell .text-field:focused {
|
|
||||||
-fx-background-insets: 0, 1;
|
|
||||||
}
|
|
||||||
/* 选项卡 */
|
|
||||||
.tab-pane {
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
.tab-pane > .tab-header-area > .headers-region > .tab {
|
|
||||||
-fx-padding: 0 0 0 .5em;
|
|
||||||
-fx-background-insets: 0 0 1 0, 0 1 1 0, 1 2 1 1;
|
|
||||||
-fx-background-radius: 0, 0, 0;
|
|
||||||
}
|
|
||||||
.tab-pane > .tab-header-area > .headers-region > .tab:selected {
|
|
||||||
-fx-background-insets: 0 1 0 0, 0 1 0 0;
|
|
||||||
}
|
|
||||||
.tab-pane > .tab-header-area > .headers-region > .tab > .tab-container > .tab-label {
|
|
||||||
-fx-padding: 0 .5em 0 0;
|
|
||||||
}
|
|
||||||
.tab-pane:top > .tab-header-area {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
/* 分割线 */
|
|
||||||
.separator > .line {
|
.separator > .line {
|
||||||
-fx-border-style: null;
|
-fx-border-style: null;
|
||||||
-fx-border-width: 0;
|
-fx-border-width: 0;
|
||||||
@@ -645,172 +426,3 @@
|
|||||||
-fx-pref-height: 1;
|
-fx-pref-height: 1;
|
||||||
-fx-background-color: -timi-fx-border-color;
|
-fx-background-color: -timi-fx-border-color;
|
||||||
}
|
}
|
||||||
/* --------------------------- 布局 --------------------------- */
|
|
||||||
/* 滚动 */
|
|
||||||
.scroll-pane {
|
|
||||||
-fx-padding: 0;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
.scroll-pane .corner {
|
|
||||||
-fx-background-color: transparent;
|
|
||||||
}
|
|
||||||
/* 分割 */
|
|
||||||
.split-pane {
|
|
||||||
-fx-padding: 0;
|
|
||||||
-fx-background-color: transparent;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
/* --------------------------- 可选类 --------------------------- */
|
|
||||||
/* 其他 */
|
|
||||||
.bg-tp,
|
|
||||||
.bg-tp .viewport {
|
|
||||||
-fx-background-color: transparent;
|
|
||||||
-fx-background-insets: 0;
|
|
||||||
}
|
|
||||||
.bg-white {
|
|
||||||
-fx-background-color: #FFF;
|
|
||||||
}
|
|
||||||
.bg-black {
|
|
||||||
-fx-background-color: #000;
|
|
||||||
}
|
|
||||||
.bg-default {
|
|
||||||
-fx-background-color: #F4F4F4;
|
|
||||||
}
|
|
||||||
.bg-button-static {
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
-fx-background-color: -fx-body-color;
|
|
||||||
}
|
|
||||||
.bg-button-static:disabled {
|
|
||||||
-fx-opacity: -timi-fx-opacity-disabled;
|
|
||||||
}
|
|
||||||
.bg-button {
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
-fx-background-color: -fx-body-color;
|
|
||||||
}
|
|
||||||
.bg-button:hover {
|
|
||||||
-fx-color: -fx-hover-base;
|
|
||||||
}
|
|
||||||
.bg-button:armed {
|
|
||||||
-fx-color: -fx-pressed-base;
|
|
||||||
}
|
|
||||||
.bg-button:disabled {
|
|
||||||
-fx-opacity: -timi-fx-opacity-disabled;
|
|
||||||
}
|
|
||||||
.hover-opacity:hover {
|
|
||||||
-fx-opacity: -timi-fx-opacity-hover;
|
|
||||||
}
|
|
||||||
/* 滚动面板的滚动条边框 */
|
|
||||||
.sp-border .scroll-bar:vertical {
|
|
||||||
-fx-border-width: 0 0 0 1;
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
.sp-border .scroll-bar:horizontal {
|
|
||||||
-fx-border-width: 1 0 0 0;
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
.sp-border .corner {
|
|
||||||
-fx-border-width: 1 0 0 1;
|
|
||||||
-fx-border-color: -timi-fx-border-color;
|
|
||||||
}
|
|
||||||
/* 内边距 */
|
|
||||||
.padding-n {
|
|
||||||
-fx-padding: 0;
|
|
||||||
}
|
|
||||||
/* 字体颜色 */
|
|
||||||
.white {
|
|
||||||
-fx-text-fill: #FFF;
|
|
||||||
}
|
|
||||||
.red {
|
|
||||||
-fx-text-fill: #F30;
|
|
||||||
}
|
|
||||||
.brown {
|
|
||||||
-fx-text-fill: #A67D7B;
|
|
||||||
}
|
|
||||||
.black {
|
|
||||||
-fx-text-fill: #000;
|
|
||||||
}
|
|
||||||
.orange {
|
|
||||||
-fx-text-fill: #F60;
|
|
||||||
}
|
|
||||||
.yellow {
|
|
||||||
-fx-text-fill: #FF0;
|
|
||||||
}
|
|
||||||
.green {
|
|
||||||
-fx-text-fill: #393;
|
|
||||||
}
|
|
||||||
.dark-green {
|
|
||||||
-fx-text-fill: #373;
|
|
||||||
}
|
|
||||||
.gray {
|
|
||||||
-fx-text-fill: #666;
|
|
||||||
}
|
|
||||||
.blue {
|
|
||||||
-fx-text-fill: #008DCB;
|
|
||||||
}
|
|
||||||
.light-blue {
|
|
||||||
-fx-text-fill: #DDEAF0;
|
|
||||||
}
|
|
||||||
.gray-white {
|
|
||||||
-fx-text-fill: #F4F4F4;
|
|
||||||
}
|
|
||||||
.light-gray {
|
|
||||||
-fx-text-fill: #B5B5B5;
|
|
||||||
}
|
|
||||||
.dark-gray {
|
|
||||||
-fx-text-fill: #333;
|
|
||||||
}
|
|
||||||
.pink {
|
|
||||||
-fx-text-fill: #FF7A9B;
|
|
||||||
}
|
|
||||||
.transparent {
|
|
||||||
-fx-text-fill: #FFFFFF00;
|
|
||||||
}
|
|
||||||
/* 边框控制 */
|
|
||||||
.border-all {
|
|
||||||
-fx-border-width: 1;
|
|
||||||
}
|
|
||||||
.border-n {
|
|
||||||
-fx-border-width: 0;
|
|
||||||
}
|
|
||||||
.border-t {
|
|
||||||
-fx-border-width: 1 0 0 0;
|
|
||||||
}
|
|
||||||
.border-r {
|
|
||||||
-fx-border-width: 0 1 0 0;
|
|
||||||
}
|
|
||||||
.border-b {
|
|
||||||
-fx-border-width: 0 0 1 0;
|
|
||||||
}
|
|
||||||
.border-l {
|
|
||||||
-fx-border-width: 0 0 0 1;
|
|
||||||
}
|
|
||||||
.border-tr {
|
|
||||||
-fx-border-width: 1 1 0 0;
|
|
||||||
}
|
|
||||||
.border-rb {
|
|
||||||
-fx-border-width: 0 1 1 0;
|
|
||||||
}
|
|
||||||
.border-bl {
|
|
||||||
-fx-border-width: 0 0 1 1;
|
|
||||||
}
|
|
||||||
.border-lt {
|
|
||||||
-fx-border-width: 1 0 0 1;
|
|
||||||
}
|
|
||||||
.border-trb {
|
|
||||||
-fx-border-width: 1 1 1 0;
|
|
||||||
}
|
|
||||||
.border-rbl {
|
|
||||||
-fx-border-width: 0 1 1 1;
|
|
||||||
}
|
|
||||||
.border-blt {
|
|
||||||
-fx-border-width: 1 0 1 1;
|
|
||||||
}
|
|
||||||
.border-ltr {
|
|
||||||
-fx-border-width: 1 1 0 1;
|
|
||||||
}
|
|
||||||
.border-tb {
|
|
||||||
-fx-border-width: 1 0 1 0;
|
|
||||||
}
|
|
||||||
.border-lr {
|
|
||||||
-fx-border-width: 0 1 0 1;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
src: url('./MinecraftAE.ttf');
|
src: url('../MinecraftAE.ttf');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Minecraft AE 字体在 16 32 64 128 像素时表现为最清晰 */
|
/* Minecraft AE 字体在 16 32 64 128 像素时表现为最清晰 */
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
.text-area,
|
.text-area,
|
||||||
.text-field,
|
.text-field,
|
||||||
.list-view > *,
|
.list-view > *,
|
||||||
|
.toggle-button,
|
||||||
.table-view > *,
|
.table-view > *,
|
||||||
.minecraft-ae {
|
.minecraft-ae {
|
||||||
-fx-font-size: 16;
|
-fx-font-size: 16;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/* --------------------------- 布局 --------------------------- */
|
||||||
|
.scroll-pane {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
}
|
||||||
|
.scroll-pane .corner {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
}
|
||||||
|
.split-pane {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@import "base.css";
|
||||||
|
@import "layout.css";
|
||||||
|
@import "utility.css";
|
||||||
|
|
||||||
|
@import "components/radio-button-group.css";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@import "base.css";
|
||||||
|
@import "controls.css";
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
/* --------------------------- 可选类 --------------------------- */
|
||||||
|
.bg-tp,
|
||||||
|
.bg-tp .viewport {
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
}
|
||||||
|
.bg-white {
|
||||||
|
-fx-background-color: -timi-fx-white-color;
|
||||||
|
}
|
||||||
|
.bg-black {
|
||||||
|
-fx-background-color: -timi-fx-black-color;
|
||||||
|
}
|
||||||
|
.bg-default {
|
||||||
|
-fx-background-color: -timi-fx-gray-white-color;
|
||||||
|
}
|
||||||
|
.bg-button-static {
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
-fx-background-color: -fx-body-color;
|
||||||
|
}
|
||||||
|
.bg-button-static:disabled {
|
||||||
|
-fx-opacity: -timi-fx-opacity-disabled;
|
||||||
|
}
|
||||||
|
.bg-button {
|
||||||
|
-fx-background-color: -fx-body-color;
|
||||||
|
}
|
||||||
|
.bg-button:hover {
|
||||||
|
-fx-color: -fx-hover-base;
|
||||||
|
}
|
||||||
|
.bg-button:armed {
|
||||||
|
-fx-color: -fx-pressed-base;
|
||||||
|
}
|
||||||
|
.bg-button:disabled {
|
||||||
|
-fx-opacity: -timi-fx-opacity-disabled;
|
||||||
|
}
|
||||||
|
.hover-opacity:hover {
|
||||||
|
-fx-opacity: -timi-fx-opacity-hover;
|
||||||
|
}
|
||||||
|
.sp-border .scroll-bar:vertical {
|
||||||
|
-fx-border-width: 0 0 0 1;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.sp-border .scroll-bar:horizontal {
|
||||||
|
-fx-border-width: 1 0 0 0;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.sp-border .corner {
|
||||||
|
-fx-border-width: 1 0 0 1;
|
||||||
|
-fx-border-color: -timi-fx-border-color;
|
||||||
|
}
|
||||||
|
.editable-table .table-row-cell:odd {
|
||||||
|
-fx-background-color: -fx-table-cell-border-color, -fx-control-inner-background;
|
||||||
|
}
|
||||||
|
.editable-table .table-row-cell:filled:selected,
|
||||||
|
.editable-table .table-row-cell:filled:selected:focused {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-text-fill: -fx-selection-bar-text;
|
||||||
|
-fx-background: -timi-fx-selected-color;
|
||||||
|
-fx-border-width: 0;
|
||||||
|
-fx-background-color: -timi-fx-selected-color;
|
||||||
|
-fx-background-insets: 0;
|
||||||
|
-fx-table-cell-border-color: -timi-fx-selected-color;
|
||||||
|
}
|
||||||
|
.editable-table .table-cell {
|
||||||
|
-fx-padding: 0;
|
||||||
|
-fx-cell-size: 0;
|
||||||
|
-fx-border-width: .083333em .083333em .083333em 0; /* 1 1 1 0 */
|
||||||
|
}
|
||||||
|
.editable-table .table-row-cell .text-field {
|
||||||
|
-fx-background-color: -timi-fx-color, -timi-fx-white-color;
|
||||||
|
-fx-background-insets: 0, 0;
|
||||||
|
}
|
||||||
|
.editable-table .table-row-cell .text-field:focused {
|
||||||
|
-fx-background-insets: 0, 1;
|
||||||
|
}
|
||||||
|
.padding-n {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
.white {
|
||||||
|
-fx-text-fill: -timi-fx-white-color;
|
||||||
|
}
|
||||||
|
.red {
|
||||||
|
-fx-text-fill: -timi-fx-red-color;
|
||||||
|
}
|
||||||
|
.brown {
|
||||||
|
-fx-text-fill: -timi-fx-brown-color;
|
||||||
|
}
|
||||||
|
.black {
|
||||||
|
-fx-text-fill: -timi-fx-black-color;
|
||||||
|
}
|
||||||
|
.orange {
|
||||||
|
-fx-text-fill: -timi-fx-orange-color;
|
||||||
|
}
|
||||||
|
.yellow {
|
||||||
|
-fx-text-fill: -timi-fx-yellow-color;
|
||||||
|
}
|
||||||
|
.green {
|
||||||
|
-fx-text-fill: -timi-fx-green-color;
|
||||||
|
}
|
||||||
|
.dark-green {
|
||||||
|
-fx-text-fill: -timi-fx-dark-green-color;
|
||||||
|
}
|
||||||
|
.gray {
|
||||||
|
-fx-text-fill: -timi-fx-gray-color;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
-fx-text-fill: -timi-fx-blue-color;
|
||||||
|
}
|
||||||
|
.light-blue {
|
||||||
|
-fx-text-fill: -timi-fx-light-blue-color;
|
||||||
|
}
|
||||||
|
.gray-white {
|
||||||
|
-fx-text-fill: -timi-fx-gray-white-color;
|
||||||
|
}
|
||||||
|
.light-gray {
|
||||||
|
-fx-text-fill: -timi-fx-light-gray-color;
|
||||||
|
}
|
||||||
|
.dark-gray {
|
||||||
|
-fx-text-fill: -timi-fx-dark-gray-color;
|
||||||
|
}
|
||||||
|
.pink {
|
||||||
|
-fx-text-fill: -timi-fx-pink-color;
|
||||||
|
}
|
||||||
|
.transparent {
|
||||||
|
-fx-text-fill: -timi-fx-transparent;
|
||||||
|
}
|
||||||
|
.border-all {
|
||||||
|
-fx-border-width: 1;
|
||||||
|
}
|
||||||
|
.border-n {
|
||||||
|
-fx-border-width: 0;
|
||||||
|
}
|
||||||
|
.border-t {
|
||||||
|
-fx-border-width: 1 0 0 0;
|
||||||
|
}
|
||||||
|
.border-r {
|
||||||
|
-fx-border-width: 0 1 0 0;
|
||||||
|
}
|
||||||
|
.border-b {
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
}
|
||||||
|
.border-l {
|
||||||
|
-fx-border-width: 0 0 0 1;
|
||||||
|
}
|
||||||
|
.border-tr {
|
||||||
|
-fx-border-width: 1 1 0 0;
|
||||||
|
}
|
||||||
|
.border-rb {
|
||||||
|
-fx-border-width: 0 1 1 0;
|
||||||
|
}
|
||||||
|
.border-bl {
|
||||||
|
-fx-border-width: 0 0 1 1;
|
||||||
|
}
|
||||||
|
.border-lt {
|
||||||
|
-fx-border-width: 1 0 0 1;
|
||||||
|
}
|
||||||
|
.border-trb {
|
||||||
|
-fx-border-width: 1 1 1 0;
|
||||||
|
}
|
||||||
|
.border-rbl {
|
||||||
|
-fx-border-width: 0 1 1 1;
|
||||||
|
}
|
||||||
|
.border-blt {
|
||||||
|
-fx-border-width: 1 0 1 1;
|
||||||
|
}
|
||||||
|
.border-ltr {
|
||||||
|
-fx-border-width: 1 1 0 1;
|
||||||
|
}
|
||||||
|
.border-tb {
|
||||||
|
-fx-border-width: 1 0 1 0;
|
||||||
|
}
|
||||||
|
.border-lr {
|
||||||
|
-fx-border-width: 0 1 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.component;
|
package com.imyeyu.fx.ui.examples.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
@@ -22,10 +22,10 @@ public abstract class AbstractDemoPane extends AbstractPane {
|
|||||||
protected Label tips;
|
protected Label tips;
|
||||||
|
|
||||||
/** 文档 */
|
/** 文档 */
|
||||||
protected XHyperlink document;
|
protected Hyperlink document;
|
||||||
|
|
||||||
/** 源码 */
|
/** 源码 */
|
||||||
protected XHyperlink source;
|
protected Hyperlink source;
|
||||||
|
|
||||||
public AbstractDemoPane() {
|
public AbstractDemoPane() {
|
||||||
// 标题
|
// 标题
|
||||||
@@ -37,11 +37,11 @@ public abstract class AbstractDemoPane extends AbstractPane {
|
|||||||
|
|
||||||
// 文档
|
// 文档
|
||||||
Label labelDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
Label labelDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
||||||
document = new XHyperlink();
|
document = new Hyperlink();
|
||||||
|
|
||||||
// 源码
|
// 源码
|
||||||
Label labelSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
source = new XHyperlink();
|
source = new Hyperlink();
|
||||||
|
|
||||||
// 提示
|
// 提示
|
||||||
tips = TimiFXUI.label();
|
tips = TimiFXUI.label();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.imyeyu.fx.bean.Interpolates;
|
|||||||
import com.imyeyu.fx.ui.MinecraftFont;
|
import com.imyeyu.fx.ui.MinecraftFont;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.SelectableLabel;
|
import com.imyeyu.fx.ui.components.SelectableLabel;
|
||||||
import com.imyeyu.fx.utils.BgFill;
|
import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
|
||||||
import com.sun.scenario.animation.SplineInterpolator;
|
import com.sun.scenario.animation.SplineInterpolator;
|
||||||
import javafx.animation.TranslateTransition;
|
import javafx.animation.TranslateTransition;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
@@ -41,7 +41,7 @@ public class InterpolatorPane extends BorderPane implements TimiFXUI {
|
|||||||
|
|
||||||
// 方块
|
// 方块
|
||||||
block = new Region();
|
block = new Region();
|
||||||
block.setBackground(BgFill.test());
|
block.setBackground(BackgroundFillBuilder.test());
|
||||||
|
|
||||||
// 轨道
|
// 轨道
|
||||||
HBox track = new HBox(block);
|
HBox track = new HBox(block);
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package com.imyeyu.fx.ui.examples.component.sidebar;
|
package com.imyeyu.fx.ui.examples.component.sidebar;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.Navigation;
|
import com.imyeyu.fx.ui.components.navigation.Navigation;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationGroup;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationItem;
|
||||||
import com.imyeyu.fx.ui.examples.service.PageService;
|
import com.imyeyu.fx.ui.examples.service.PageService;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导航
|
* 导航
|
||||||
@@ -15,6 +19,9 @@ import javafx.scene.control.ToggleButton;
|
|||||||
@Component
|
@Component
|
||||||
public class Sidebar extends Navigation {
|
public class Sidebar extends Navigation {
|
||||||
|
|
||||||
|
/** 侧边栏项目映射 */
|
||||||
|
private final Map<SidebarItem, Item> itemMap = new EnumMap<>(SidebarItem.class);
|
||||||
|
|
||||||
public Sidebar(PageService pageService) {
|
public Sidebar(PageService pageService) {
|
||||||
|
|
||||||
Item welcome = new Item(SidebarItem.WELCOME);
|
Item welcome = new Item(SidebarItem.WELCOME);
|
||||||
@@ -24,31 +31,29 @@ public class Sidebar extends Navigation {
|
|||||||
Item alert = new Item(SidebarItem.ALERT);
|
Item alert = new Item(SidebarItem.ALERT);
|
||||||
Item popupTips = new Item(SidebarItem.POPUP_TIPS);
|
Item popupTips = new Item(SidebarItem.POPUP_TIPS);
|
||||||
Item runAsync = new Item(SidebarItem.RUN_ASYNC);
|
Item runAsync = new Item(SidebarItem.RUN_ASYNC);
|
||||||
Item animationRenderer = new Item(SidebarItem.ANIMATION_RENDERER);
|
|
||||||
|
|
||||||
add(welcome, style, extendTools, bindingConfig, alert, popupTips, runAsync, animationRenderer);
|
add(welcome, style, extendTools, bindingConfig, alert, popupTips, runAsync);
|
||||||
|
|
||||||
// 动画
|
// 动画
|
||||||
Item interpolator = new Item(SidebarItem.INTERPOLATOR);
|
Item interpolator = new Item(SidebarItem.INTERPOLATOR);
|
||||||
Item smoothScroll = new Item(SidebarItem.SMOOTH_SCROLL);
|
Item smoothScroll = new Item(SidebarItem.SMOOTH_SCROLL);
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("animation"), interpolator, smoothScroll);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("animation")).add(interpolator, smoothScroll));
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
SidebarItem[] components = {SidebarItem.CHECK_BOX_PICKER, SidebarItem.DATE_TIME_PICKER, SidebarItem.EDITABLE_TABLE_CELL, SidebarItem.FILE_TREE_VIEW, SidebarItem.ICON_BUTTON, SidebarItem.ICON_PICKER, SidebarItem.LABEL_PROGRESS_BAR, SidebarItem.NAVIGATION, SidebarItem.NUMBER_FIELD, SidebarItem.PROGRESS_SLIDER, SidebarItem.SELECTABLE_LABEL, SidebarItem.TEXT_AREA_EDITOR, SidebarItem.TITLE_LABEL, SidebarItem.TOGGLE_ICON, SidebarItem.X_PAGINATION, SidebarItem.X_TAB_PANE, SidebarItem.X_TREE_VIEW};
|
SidebarItem[] components = {SidebarItem.BUTTON, SidebarItem.DATE_TIME_PICKER, SidebarItem.EDITABLE_TABLE_CELL, SidebarItem.FILE_TREE_VIEW, SidebarItem.ICON_BUTTON, SidebarItem.ICON_PICKER, SidebarItem.LABEL_PROGRESS_BAR, SidebarItem.NAVIGATION, SidebarItem.NUMBER_FIELD, SidebarItem.FILLED_SLIDER, SidebarItem.SELECTABLE_LABEL, SidebarItem.TEXT_AREA_EDITOR, SidebarItem.TITLE_LABEL, SidebarItem.TOGGLE_ICON, SidebarItem.X_PAGINATION, SidebarItem.X_TAB_PANE, SidebarItem.X_TREE_VIEW};
|
||||||
Item[] componentItems = new Item[components.length];
|
Item[] componentItems = new Item[components.length];
|
||||||
for (int i = 0; i < componentItems.length; i++) {
|
for (int i = 0; i < componentItems.length; i++) {
|
||||||
componentItems[i] = new Item(components[i]);
|
componentItems[i] = new Item(components[i]);
|
||||||
}
|
}
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("component"), componentItems);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("component")).add(componentItems));
|
||||||
|
|
||||||
// 其他
|
// 其他
|
||||||
Item draggableNode = new Item(SidebarItem.DRAGGABLE_NODE);
|
Item draggableNode = new Item(SidebarItem.DRAGGABLE_NODE);
|
||||||
Item draggableWindow = new Item(SidebarItem.DRAGGABLE_WINDOW);
|
Item draggableWindow = new Item(SidebarItem.DRAGGABLE_WINDOW);
|
||||||
Item screen = new Item(SidebarItem.SCREEN);
|
Item screen = new Item(SidebarItem.SCREEN);
|
||||||
Item tray = new Item(SidebarItem.TRAY);
|
Item tray = new Item(SidebarItem.TRAY);
|
||||||
addGroup(TimiFXUI.MULTILINGUAL.text("other"), draggableNode, draggableWindow, screen, tray);
|
add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("other")).add(draggableNode, draggableWindow, screen, tray));
|
||||||
|
setBorder(Stroke.RIGHT);
|
||||||
getStyleClass().add(CSS.BORDER_R);
|
|
||||||
setMinWidth(140);
|
setMinWidth(140);
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
// ---------- 事件 ----------
|
||||||
@@ -67,13 +72,12 @@ public class Sidebar extends Navigation {
|
|||||||
* @param item 选中项
|
* @param item 选中项
|
||||||
*/
|
*/
|
||||||
public void setSelected(SidebarItem item) {
|
public void setSelected(SidebarItem item) {
|
||||||
for (int i = 0; i < items.size(); i++) {
|
Item selected = itemMap.get(item);
|
||||||
if (items.get(i) instanceof Item it && it.item == item) {
|
if (selected != null) {
|
||||||
setSelectedItem(items.get(i));
|
setSelectedItem(selected);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
throw new NullPointerException("not found item page for %s".formatted(item));
|
||||||
throw new NullPointerException("not found item page for " + item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,14 +86,20 @@ public class Sidebar extends Navigation {
|
|||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-02-22 19:45
|
* @since 2022-02-22 19:45
|
||||||
*/
|
*/
|
||||||
private static class Item extends ToggleButton {
|
private class Item extends NavigationItem {
|
||||||
|
|
||||||
/** 列表项对象 */
|
/** 列表项对象 */
|
||||||
final SidebarItem item;
|
final SidebarItem item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建侧边栏项目
|
||||||
|
*
|
||||||
|
* @param item 侧边栏项目
|
||||||
|
*/
|
||||||
public Item(SidebarItem item) {
|
public Item(SidebarItem item) {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
setText(item.text);
|
setText(item.text);
|
||||||
|
itemMap.put(item, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import com.imyeyu.fx.ui.TimiFXUI;
|
|||||||
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.AlertDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.AlertDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.AnimationRendererDemo;
|
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.BindingsConfigDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.BindingsConfigDemo;
|
||||||
|
import com.imyeyu.fx.ui.examples.view.pages.ButtonDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.ExtendDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.ExtendDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.PopupTipsDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.PopupTipsDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.RunAsyncDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.RunAsyncDemo;
|
||||||
@@ -13,7 +13,6 @@ import com.imyeyu.fx.ui.examples.view.pages.Style;
|
|||||||
import com.imyeyu.fx.ui.examples.view.pages.Welcome;
|
import com.imyeyu.fx.ui.examples.view.pages.Welcome;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.animation.InterpolatorDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.animation.InterpolatorDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.animation.SmoothScrollDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.animation.SmoothScrollDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.CheckBoxPickerDemo;
|
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.DateTimePickerDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.DateTimePickerDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.EditableTableCellDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.EditableTableCellDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.FileTreeViewDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.FileTreeViewDemo;
|
||||||
@@ -22,7 +21,7 @@ import com.imyeyu.fx.ui.examples.view.pages.component.IconPickerDemo;
|
|||||||
import com.imyeyu.fx.ui.examples.view.pages.component.LabelProgressBarDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.LabelProgressBarDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.NavigationDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.NavigationDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.NumberFieldDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.NumberFieldDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.ProgressSliderDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.FilledSliderDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.SelectableLabelDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.SelectableLabelDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.TextAreaEditorDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.TextAreaEditorDemo;
|
||||||
import com.imyeyu.fx.ui.examples.view.pages.component.TitleLabelDemo;
|
import com.imyeyu.fx.ui.examples.view.pages.component.TitleLabelDemo;
|
||||||
@@ -69,9 +68,6 @@ public enum SidebarItem {
|
|||||||
/** 异步任务 */
|
/** 异步任务 */
|
||||||
RUN_ASYNC(RunAsyncDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.run_async")),
|
RUN_ASYNC(RunAsyncDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.run_async")),
|
||||||
|
|
||||||
/** 异步任务 */
|
|
||||||
ANIMATION_RENDERER(AnimationRendererDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer")),
|
|
||||||
|
|
||||||
// ---------- 动画 ----------
|
// ---------- 动画 ----------
|
||||||
|
|
||||||
/** 动画插值器 */
|
/** 动画插值器 */
|
||||||
@@ -82,8 +78,8 @@ public enum SidebarItem {
|
|||||||
|
|
||||||
// ---------- 组件 ----------
|
// ---------- 组件 ----------
|
||||||
|
|
||||||
/** 复选框选择器 */
|
/** 按钮组 */
|
||||||
CHECK_BOX_PICKER(CheckBoxPickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.check_box_picker")),
|
BUTTON(ButtonDemo.class, "切换按钮组"),
|
||||||
|
|
||||||
/** 详细时间选择器 */
|
/** 详细时间选择器 */
|
||||||
DATE_TIME_PICKER(DateTimePickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.date_time_picker")),
|
DATE_TIME_PICKER(DateTimePickerDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.date_time_picker")),
|
||||||
@@ -110,7 +106,7 @@ public enum SidebarItem {
|
|||||||
NUMBER_FIELD(NumberFieldDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.number_field")),
|
NUMBER_FIELD(NumberFieldDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.number_field")),
|
||||||
|
|
||||||
/** 进度调整 */
|
/** 进度调整 */
|
||||||
PROGRESS_SLIDER(ProgressSliderDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.progress_slider")),
|
FILLED_SLIDER(FilledSliderDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.progress_slider")),
|
||||||
|
|
||||||
/** 可选标签 */
|
/** 可选标签 */
|
||||||
SELECTABLE_LABEL(SelectableLabelDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.selectable_label")),
|
SELECTABLE_LABEL(SelectableLabelDemo.class, TimiFXUI.MULTILINGUAL.text("fx.example.selectable_label")),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import javafx.scene.image.Image;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class Resources implements TimiFXUI {
|
public class Resources implements TimiFXUI {
|
||||||
|
|
||||||
public static final Image ICON_X64 = new Image(RESOURCE + "icon.png", 64, 64, true, false);
|
public static final Image ICON_X64 = new Image(RESOURCE + "/icon.png", 64, 64, true, false);
|
||||||
|
|
||||||
/** @return 配置 */
|
/** @return 配置 */
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view;
|
package com.imyeyu.fx.ui.examples.view;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.examples.bean.Config;
|
||||||
|
import com.imyeyu.fx.ui.examples.component.RootLayout;
|
||||||
|
import com.imyeyu.inject.annotation.Inject;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.scene.PerspectiveCamera;
|
import javafx.scene.PerspectiveCamera;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.ui.examples.bean.Config;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.RootLayout;
|
|
||||||
import com.imyeyu.inject.annotation.Inject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主界面
|
* 主界面
|
||||||
@@ -26,14 +26,8 @@ public abstract class ViewMain extends Application implements TimiFXUI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(final Stage stage) {
|
public void start(final Stage stage) {
|
||||||
PerspectiveCamera perspectiveCamera = new PerspectiveCamera(false);
|
|
||||||
perspectiveCamera.setTranslateX(0);
|
|
||||||
perspectiveCamera.setTranslateY(0);
|
|
||||||
perspectiveCamera.setTranslateZ(0);
|
|
||||||
|
|
||||||
Scene scene = new Scene(root);
|
Scene scene = new Scene(root);
|
||||||
scene.getStylesheets().addAll(CSS_STYLE, CSS_FONT);
|
TimiFXUI.applyStyle(scene);
|
||||||
scene.setCamera(perspectiveCamera);
|
|
||||||
stage.setTitle(TimiFXUI.MULTILINGUAL.text("fx.example.title"));
|
stage.setTitle(TimiFXUI.MULTILINGUAL.text("fx.example.title"));
|
||||||
stage.getIcons().add(new Image(RESOURCE + "icon.png"));
|
stage.getIcons().add(new Image(RESOURCE + "icon.png"));
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import com.imyeyu.fx.ui.components.alert.AlertTips;
|
|||||||
import com.imyeyu.fx.ui.components.alert.AlertType;
|
import com.imyeyu.fx.ui.components.alert.AlertType;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
@@ -26,8 +26,14 @@ import javafx.scene.control.CheckBox;
|
|||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.control.SelectionMode;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
|
import javafx.scene.layout.BorderStroke;
|
||||||
|
import javafx.scene.layout.BorderStrokeStyle;
|
||||||
|
import javafx.scene.layout.BorderWidths;
|
||||||
|
import javafx.scene.layout.CornerRadii;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹出窗体
|
* 弹出窗体
|
||||||
@@ -45,47 +51,47 @@ public class AlertDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
// 一般
|
// 一般
|
||||||
Button info = new Button(TimiFXUI.MULTILINGUAL.text("info"));
|
Button info = new Button(TimiFXUI.MULTILINGUAL.text("info"));
|
||||||
info.getStyleClass().add(CSS.BORDER_BLT);
|
info.setBorder(Stroke.EX_RIGHT);
|
||||||
Button warning = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
Button warning = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
||||||
warning.getStyleClass().add(CSS.BORDER_BLT);
|
warning.setBorder(Stroke.EX_RIGHT);
|
||||||
Button warningDanger = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
Button warningDanger = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
||||||
warningDanger.getStyleClass().add(CSS.BORDER_BLT);
|
warningDanger.setBorder(Stroke.EX_RIGHT);
|
||||||
Button error = new Button(TimiFXUI.MULTILINGUAL.text("error"));
|
Button error = new Button(TimiFXUI.MULTILINGUAL.text("error"));
|
||||||
error.getStyleClass().add(CSS.BORDER_BLT);
|
error.setBorder(Stroke.EX_RIGHT);
|
||||||
Button deadlyError = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.deadly_error"));
|
Button deadlyError = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.deadly_error"));
|
||||||
|
|
||||||
// 询问
|
// 询问
|
||||||
Button confirmInfo = new Button(TimiFXUI.MULTILINGUAL.text("info"));
|
Button confirmInfo = new Button(TimiFXUI.MULTILINGUAL.text("info"));
|
||||||
confirmInfo.getStyleClass().add(CSS.BORDER_BLT);
|
confirmInfo.setBorder(Stroke.EX_RIGHT);
|
||||||
Button confirmWarning = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
Button confirmWarning = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
||||||
confirmWarning.getStyleClass().add(CSS.BORDER_BLT);
|
confirmWarning.setBorder(Stroke.EX_RIGHT);
|
||||||
Button confirmWarningDanger = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
Button confirmWarningDanger = new Button(TimiFXUI.MULTILINGUAL.text("warning"));
|
||||||
confirmWarningDanger.getStyleClass().add(CSS.BORDER_BLT);
|
confirmWarningDanger.setBorder(Stroke.EX_RIGHT);
|
||||||
Button confirmError = new Button(TimiFXUI.MULTILINGUAL.text("error"));
|
Button confirmError = new Button(TimiFXUI.MULTILINGUAL.text("error"));
|
||||||
confirmError.getStyleClass().add(CSS.BORDER_BLT);
|
confirmError.setBorder(Stroke.EX_RIGHT);
|
||||||
Button confirmCancel = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.can_cancel"));
|
Button confirmCancel = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.can_cancel"));
|
||||||
|
|
||||||
// 输入
|
// 输入
|
||||||
Button textField = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.text_field"));
|
Button textField = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.text_field"));
|
||||||
textField.getStyleClass().add(CSS.BORDER_BLT);
|
textField.setBorder(Stroke.EX_RIGHT);
|
||||||
Button textArea = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.text_area"));
|
Button textArea = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.text_area"));
|
||||||
|
|
||||||
// 文件
|
// 文件
|
||||||
Button file = new Button(TimiFXUI.MULTILINGUAL.text("file.select"));
|
Button file = new Button(TimiFXUI.MULTILINGUAL.text("file.select"));
|
||||||
file.getStyleClass().add(CSS.BORDER_BLT);
|
file.setBorder(Stroke.EX_RIGHT);
|
||||||
Button directory = new Button(TimiFXUI.MULTILINGUAL.text("file.select.directory"));
|
Button directory = new Button(TimiFXUI.MULTILINGUAL.text("file.select.directory"));
|
||||||
directory.getStyleClass().add(CSS.BORDER_BLT);
|
directory.setBorder(Stroke.EX_RIGHT);
|
||||||
Button fileBlend = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.file_blend"));
|
Button fileBlend = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.alert.file_blend"));
|
||||||
|
|
||||||
// 加载中
|
// 加载中
|
||||||
Button loading = new Button(TimiFXUI.MULTILINGUAL.text("loading"));
|
Button loading = new Button(TimiFXUI.MULTILINGUAL.text("loading"));
|
||||||
loading.getStyleClass().add(CSS.BORDER_BLT);
|
loading.setBorder(Stroke.EX_RIGHT);
|
||||||
|
|
||||||
// 自定义
|
// 自定义
|
||||||
Button custom = new Button(TimiFXUI.MULTILINGUAL.text("custom"));
|
Button custom = new Button(TimiFXUI.MULTILINGUAL.text("custom"));
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.KEY);
|
getColumnConstraints().addAll(Column.key(), Column.key());
|
||||||
setHgap(12);
|
setHgap(12);
|
||||||
setVgap(6);
|
setVgap(6);
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.BindingUtils;
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.ui.components.SelectableLabel;
|
|
||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
|
||||||
import com.imyeyu.fx.ui.components.popup.PopupTipsService;
|
|
||||||
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
|
||||||
import com.imyeyu.fx.ui.examples.ctrl.Main;
|
|
||||||
import com.imyeyu.fx.utils.AnimationRenderer;
|
|
||||||
import com.imyeyu.fx.utils.Column;
|
|
||||||
import com.imyeyu.inject.annotation.Component;
|
|
||||||
import com.imyeyu.io.IO;
|
|
||||||
import com.imyeyu.utils.OS;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Point3D;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.control.SplitPane;
|
|
||||||
import javafx.scene.layout.BorderPane;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.paint.PhongMaterial;
|
|
||||||
import javafx.scene.shape.Box;
|
|
||||||
import javafx.scene.shape.CullFace;
|
|
||||||
import javafx.scene.shape.DrawMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动画渲染器
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2023-04-13 10:46
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class AnimationRendererDemo extends AbstractDemoPane implements OS.FileSystem {
|
|
||||||
|
|
||||||
private final AnimationRenderer renderer;
|
|
||||||
|
|
||||||
public AnimationRendererDemo() {
|
|
||||||
title.setText(SidebarItem.ANIMATION_RENDERER.getText());
|
|
||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/extend/AnimationRenderer.html");
|
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/extend/AnimationRenderer.java");
|
|
||||||
tips.setText(TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer.tips"));
|
|
||||||
|
|
||||||
// 动画旋转立方体
|
|
||||||
Box box = new Box(128, 128, 128);
|
|
||||||
box.setDrawMode(DrawMode.LINE);
|
|
||||||
box.setCullFace(CullFace.BACK);
|
|
||||||
box.setMaterial(new PhongMaterial(Colorful.BLACK));
|
|
||||||
box.setTranslateY(60);
|
|
||||||
box.setRotationAxis(new Point3D(0, 64, 0));
|
|
||||||
renderer = new AnimationRenderer();
|
|
||||||
renderer.addRenderCallback(deltaSecond -> box.setRotate(box.getRotate() + 90 * deltaSecond));
|
|
||||||
|
|
||||||
String value = System.getProperty("javafx.animation.fullspeed");
|
|
||||||
boolean isFullSpeed = value != null && value.equalsIgnoreCase("true");
|
|
||||||
|
|
||||||
// 当前状态
|
|
||||||
Label labelStatus = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer.status"));
|
|
||||||
SelectableLabel status = new SelectableLabel("-Djavafx.animation.fullspeed=" + isFullSpeed);
|
|
||||||
|
|
||||||
// 重启
|
|
||||||
Button restart = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer.restart"));
|
|
||||||
|
|
||||||
// 示例
|
|
||||||
Label labelDemo = TimiFXUI.title(TimiFXUI.MULTILINGUAL.text("example"));
|
|
||||||
TextAreaEditor demo = new TextAreaEditor();
|
|
||||||
demo.getStyleClass().add(CSS.BORDER_N);
|
|
||||||
demo.setEditable(false);
|
|
||||||
demo.setText("""
|
|
||||||
Box box = new Box(128, 128, 128);
|
|
||||||
box.setDrawMode(DrawMode.LINE);
|
|
||||||
box.setCullFace(CullFace.BACK);
|
|
||||||
box.setMaterial(new PhongMaterial(RED));
|
|
||||||
box.setRotationAxis(new Point3D(0, 64, 0));
|
|
||||||
|
|
||||||
// 每秒 90 度旋转一个 3D 立方体,默认 60 FPS
|
|
||||||
AnimationRenderer renderer = new AnimationRenderer();
|
|
||||||
renderer.addRenderCallback(deltaSecond -> {
|
|
||||||
box.setRotate(box.getRotate() + 90 * deltaSecond);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 控制 FPS
|
|
||||||
Slider fps = new Slider(5, 240, 60);
|
|
||||||
fps.valueProperty().addListener((obs, o, newFps) -> {
|
|
||||||
renderer.setPrefFPS(newFps.intValue())
|
|
||||||
});
|
|
||||||
""".trim());
|
|
||||||
|
|
||||||
// 预设 FPS
|
|
||||||
Label labelPrefFPS = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.animation_renderer.pref_fps"));
|
|
||||||
Slider prefFPS = new Slider(5, 240, 60);
|
|
||||||
prefFPS.valueProperty().addListener((obs, o, newFps) -> renderer.setPrefFPS(newFps.intValue()));
|
|
||||||
PopupTipsService.installBindingText(prefFPS, BindingUtils.integerStringBinding(prefFPS.valueProperty()));
|
|
||||||
renderer.setPrefFPS((int) prefFPS.getValue());
|
|
||||||
|
|
||||||
// 当前渲染 FPS
|
|
||||||
Label labelFPS = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fps"));
|
|
||||||
Label fps = new Label();
|
|
||||||
fps.textProperty().bind(renderer.fpsProperty().asString("%d"));
|
|
||||||
|
|
||||||
Label labelMPF = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("mpf"));
|
|
||||||
Label mpf = new Label();
|
|
||||||
mpf.textProperty().bind(renderer.mpfProperty().asString("%.2f ms"));
|
|
||||||
|
|
||||||
setCenter(new BorderPane() {{
|
|
||||||
setTop(new GridPane() {{
|
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
|
||||||
setVgap(6);
|
|
||||||
setHgap(6);
|
|
||||||
setPadding(new Insets(20));
|
|
||||||
|
|
||||||
addRow(0, labelStatus, status);
|
|
||||||
add(restart, 1, 1);
|
|
||||||
}});
|
|
||||||
setCenter(new BorderPane() {{
|
|
||||||
setBorder(Stroke.TOP);
|
|
||||||
setTop(labelDemo);
|
|
||||||
setCenter(new SplitPane() {{
|
|
||||||
setBorder(Stroke.TOP);
|
|
||||||
setDividerPositions(.5);
|
|
||||||
getItems().addAll(demo, new BorderPane() {{
|
|
||||||
setTop(new GridPane() {{
|
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
|
||||||
setHgap(6);
|
|
||||||
setVgap(6);
|
|
||||||
setPadding(new Insets(8, 12, 8, 12));
|
|
||||||
setBorder(Stroke.BOTTOM);
|
|
||||||
|
|
||||||
int row = 0;
|
|
||||||
addRow(row++, labelPrefFPS, prefFPS);
|
|
||||||
addRow(row++, labelFPS, fps);
|
|
||||||
addRow(row, labelMPF, mpf);
|
|
||||||
}});
|
|
||||||
setCenter(box);
|
|
||||||
}});
|
|
||||||
}});
|
|
||||||
}});
|
|
||||||
}});
|
|
||||||
|
|
||||||
// ---------- 事件 ----------
|
|
||||||
|
|
||||||
restart.setOnAction(e -> {
|
|
||||||
// JRE
|
|
||||||
String jre = System.getProperty("java.home") + SEP + "bin" + SEP + "java";
|
|
||||||
// 启动参数
|
|
||||||
String param = " -Djavafx.animation.fullspeed=%s -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -jar ".formatted(!isFullSpeed);
|
|
||||||
// 启动 Jar
|
|
||||||
String jar = IO.getJarAbsolutePath(getClass());
|
|
||||||
// 重启
|
|
||||||
try {
|
|
||||||
TimiFX.doRestart(TimiFXExamples.getInject().getBean(Main.class), jre + param + jar);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
AlertTips.error(getScene().getWindow(), TimiFXUI.MULTILINGUAL.text("tips.restart.error"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onShow() {
|
|
||||||
renderer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHide() {
|
|
||||||
renderer.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,8 @@ package com.imyeyu.fx.ui.examples.view.pages;
|
|||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.examples.bean.Config;
|
import com.imyeyu.fx.ui.examples.bean.Config;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
@@ -36,10 +35,9 @@ public class BindingsConfigDemo extends AbstractDemoPane {
|
|||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/config/BindingsConfig.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/config/BindingsConfig.java");
|
||||||
|
|
||||||
// timi-java 说明
|
// timi-java 说明
|
||||||
TextFlower timijavaTips = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.tips"));
|
Hyperlink timijavaDescription = new Hyperlink("https://www.imyeyu.net/article/public/aid117.html#配置系统");
|
||||||
XHyperlink timijavaDescription = new XHyperlink("https://www.imyeyu.net/article/public/aid117.html#配置系统");
|
Hyperlink timijavaDocument = new Hyperlink("https://doc.imyeyu.net/timi-java/net/imyeyu/timijava/config/package-summary.html");
|
||||||
XHyperlink timijavaDocument = new XHyperlink("https://doc.imyeyu.net/timi-java/net/imyeyu/timijava/config/package-summary.html");
|
Hyperlink timijavaSource = new Hyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
|
||||||
XHyperlink timijavaSource = new XHyperlink("https://git.imyeyu.net/Timi/timi-java/src/master/src/main/java/net/imyeyu/timijava/config");
|
|
||||||
|
|
||||||
// 窗体尺寸
|
// 窗体尺寸
|
||||||
stageSize = new Label();
|
stageSize = new Label();
|
||||||
@@ -69,7 +67,6 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
|
|||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
add(timijavaTips, 0, row++, 2, 1);
|
|
||||||
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description")), timijavaDescription);
|
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description")), timijavaDescription);
|
||||||
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document")), timijavaDocument);
|
addRow(row++, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document")), timijavaDocument);
|
||||||
addRow(row, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source")), timijavaSource);
|
addRow(row, TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source")), timijavaSource);
|
||||||
@@ -86,7 +83,6 @@ BindingsConfig.cfg(config).bindDoubleProperty(duration, Config.section("Interpol
|
|||||||
}});
|
}});
|
||||||
setBottom(new BorderPane() {{
|
setBottom(new BorderPane() {{
|
||||||
setMargin(code, new Insets(12, 0, 0, 0));
|
setMargin(code, new Insets(12, 0, 0, 0));
|
||||||
setTop(new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.binding_config.description")));
|
|
||||||
setCenter(code);
|
setCenter(code);
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.RadioButtonGroup;
|
||||||
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
|
import com.imyeyu.inject.annotation.Component;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮组件示例
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-06-25
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ButtonDemo extends AbstractDemoPane {
|
||||||
|
|
||||||
|
public ButtonDemo() {
|
||||||
|
title.setText(SidebarItem.BUTTON.getText());
|
||||||
|
document.setText("暂无");
|
||||||
|
document.setUrl("");
|
||||||
|
source.setText("src/main/java/com/imyeyu/fx/ui/components/RadioButtonGroup.java");
|
||||||
|
source.setUrl("");
|
||||||
|
tips.setText("演示 RadioButtonGroup 的按钮模式和滑块模式,按钮列表、选中状态和允许取消选择都是组件对外暴露的标准属性");
|
||||||
|
|
||||||
|
RadioButtonGroup buttonModeGroup = new RadioButtonGroup();
|
||||||
|
buttonModeGroup.addButton("全部");
|
||||||
|
buttonModeGroup.addButton("启用");
|
||||||
|
buttonModeGroup.addButton("停用");
|
||||||
|
buttonModeGroup.setSelectedIndex(0);
|
||||||
|
|
||||||
|
RadioButtonGroup sliderModeGroup = new RadioButtonGroup();
|
||||||
|
sliderModeGroup.setMode(RadioButtonGroup.Mode.SLIDER);
|
||||||
|
sliderModeGroup.addButton("左对齐");
|
||||||
|
sliderModeGroup.addButton("居中");
|
||||||
|
sliderModeGroup.addButton("右对齐");
|
||||||
|
sliderModeGroup.setSelectedIndex(1);
|
||||||
|
|
||||||
|
RadioButtonGroup clearableGroup = new RadioButtonGroup();
|
||||||
|
clearableGroup.setMode(RadioButtonGroup.Mode.SLIDER);
|
||||||
|
clearableGroup.setAllowClearSelection(true);
|
||||||
|
clearableGroup.addButton("日");
|
||||||
|
clearableGroup.addButton("周");
|
||||||
|
clearableGroup.addButton("月");
|
||||||
|
clearableGroup.addButton("年");
|
||||||
|
clearableGroup.setSelectedIndex(2);
|
||||||
|
|
||||||
|
Label selectedButtonText = TimiFXUI.label();
|
||||||
|
Label selectedIndexText = TimiFXUI.label();
|
||||||
|
selectedButtonText.setText("当前选中: " + clearableGroup.getSelectedButton().getText());
|
||||||
|
selectedIndexText.setText("当前下标: " + clearableGroup.getSelectedIndex());
|
||||||
|
clearableGroup.selectedButtonProperty().addListener((obs, o, button) -> {
|
||||||
|
if (button == null) {
|
||||||
|
selectedButtonText.setText("当前选中: 无");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedButtonText.setText("当前选中: " + button.getText());
|
||||||
|
});
|
||||||
|
clearableGroup.selectedIndexProperty().addListener((obs, o, index) -> selectedIndexText.setText("当前下标: " + index.intValue()));
|
||||||
|
|
||||||
|
RadioButtonGroup customButtonGroup = new RadioButtonGroup();
|
||||||
|
ToggleButton primary = new ToggleButton("概览");
|
||||||
|
ToggleButton analysis = new ToggleButton("分析");
|
||||||
|
ToggleButton history = new ToggleButton("历史");
|
||||||
|
customButtonGroup.getButtons().addAll(primary, analysis, history);
|
||||||
|
customButtonGroup.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
customButtonGroup.setSelectedButton(analysis);
|
||||||
|
|
||||||
|
setCenter(new VBox() {{
|
||||||
|
setSpacing(12);
|
||||||
|
setPadding(new Insets(20));
|
||||||
|
getChildren().addAll(
|
||||||
|
new GridPane() {{
|
||||||
|
setHgap(12);
|
||||||
|
setVgap(10);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
addRow(row++, TimiFXUI.label("按钮模式"), buttonModeGroup);
|
||||||
|
addRow(row++, TimiFXUI.label("滑块模式"), sliderModeGroup);
|
||||||
|
addRow(row++, TimiFXUI.label("允许取消"), new HBox(clearableGroup));
|
||||||
|
addRow(row, TimiFXUI.label("外部按钮"), customButtonGroup);
|
||||||
|
}},
|
||||||
|
selectedButtonText,
|
||||||
|
selectedIndexText
|
||||||
|
);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
@@ -81,7 +81,7 @@ public class ExtendDemo extends AbstractDemoPane {
|
|||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/extend/XAnchorPane.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/extend/XAnchorPane.java");
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
SmoothScroll.scrollPane(this);
|
SmoothScroll.pane.install(this);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,10 +97,10 @@ public class ExtendDemo extends AbstractDemoPane {
|
|||||||
final TitleLabel title = new TitleLabel();
|
final TitleLabel title = new TitleLabel();
|
||||||
|
|
||||||
/** 文档 */
|
/** 文档 */
|
||||||
final XHyperlink document = new XHyperlink();
|
final Hyperlink document = new Hyperlink();
|
||||||
|
|
||||||
/** 源码 */
|
/** 源码 */
|
||||||
final XHyperlink source = new XHyperlink();
|
final Hyperlink source = new Hyperlink();
|
||||||
|
|
||||||
public Item() {
|
public Item() {
|
||||||
setPadding(new Insets(0, 0, 32, 0));
|
setPadding(new Insets(0, 0, 32, 0));
|
||||||
|
|||||||
@@ -35,21 +35,21 @@ public class PopupTipsDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
// 长文本
|
// 长文本
|
||||||
Button textLong = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.popup_tips.text_long"));
|
Button textLong = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.popup_tips.text_long"));
|
||||||
textLong.getStyleClass().add(CSS.BORDER_TRB);
|
textLong.setBorder(Stroke.EX_LEFT);
|
||||||
PopupTipsService.installText(textLong, TimiFXUI.MULTILINGUAL.text("fx.example.demo.text_long"));
|
PopupTipsService.installText(textLong, TimiFXUI.MULTILINGUAL.text("fx.example.demo.text_long"));
|
||||||
|
|
||||||
// 图片
|
// 图片
|
||||||
Button image = new Button(TimiFXUI.MULTILINGUAL.text("image"));
|
Button image = new Button(TimiFXUI.MULTILINGUAL.text("image"));
|
||||||
image.getStyleClass().add(CSS.BORDER_TRB);
|
image.setBorder(Stroke.EX_LEFT);
|
||||||
PopupTipsService.installImage(image, new Image(RESOURCE + "icon.png", 64, 64, false, false));
|
PopupTipsService.installImage(image, new Image(RESOURCE + "icon.png", 64, 64, false, false));
|
||||||
|
|
||||||
// 自定义
|
// 自定义
|
||||||
Button custom = new Button(TimiFXUI.MULTILINGUAL.text("custom"));
|
Button custom = new Button(TimiFXUI.MULTILINGUAL.text("custom"));
|
||||||
custom.getStyleClass().add(CSS.BORDER_TRB);
|
custom.setBorder(Stroke.EX_LEFT);
|
||||||
|
|
||||||
// 保持显示
|
// 保持显示
|
||||||
Button keepShow = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.popup_tips.keep_show"));
|
Button keepShow = new Button(TimiFXUI.MULTILINGUAL.text("fx.example.popup_tips.keep_show"));
|
||||||
keepShow.getStyleClass().add(CSS.BORDER_TRB);
|
keepShow.setBorder(Stroke.EX_LEFT);
|
||||||
{
|
{
|
||||||
ListView<String> list = new ListView<>();
|
ListView<String> list = new ListView<>();
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.imyeyu.fx.ui.examples.view.pages;
|
|||||||
import com.imyeyu.fx.task.RunAsyncScheduled;
|
import com.imyeyu.fx.task.RunAsyncScheduled;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
@@ -31,22 +30,11 @@ public class RunAsyncDemo extends AbstractDemoPane {
|
|||||||
Label title = new Label(TimiFXUI.MULTILINGUAL.text("important"));
|
Label title = new Label(TimiFXUI.MULTILINGUAL.text("important"));
|
||||||
title.setTextFill(Colorful.RED);
|
title.setTextFill(Colorful.RED);
|
||||||
|
|
||||||
// 提示 0
|
|
||||||
TextFlower tips0 = new TextFlower().textStart();
|
|
||||||
tips0.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.tips0"));
|
|
||||||
|
|
||||||
// 提示 1
|
|
||||||
TextFlower tips1 = new TextFlower().textStart();
|
|
||||||
tips1.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.tips1"));
|
|
||||||
|
|
||||||
// 时间示例
|
// 时间示例
|
||||||
Label time = new Label();
|
Label time = new Label();
|
||||||
RunAsyncScheduled.call(Duration.seconds(1), Time::now, t -> time.setText(Time.toDateTime(t)));
|
RunAsyncScheduled.call(Duration.seconds(1), Time::now, t -> time.setText(Time.toDateTime(t)));
|
||||||
|
|
||||||
// 扩展说明
|
|
||||||
TextFlower description = new TextFlower();
|
|
||||||
description.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.run_async.description"));
|
|
||||||
|
|
||||||
// 代码示例
|
// 代码示例
|
||||||
TextAreaEditor code = new TextAreaEditor();
|
TextAreaEditor code = new TextAreaEditor();
|
||||||
code.setEditable(false);
|
code.setEditable(false);
|
||||||
@@ -69,7 +57,7 @@ RunAsyncScheduled.call(Duration.seconds(1), () -> {
|
|||||||
setTop(new VBox() {{
|
setTop(new VBox() {{
|
||||||
setMargin(time, new Insets(20, 0, 0, 0));
|
setMargin(time, new Insets(20, 0, 0, 0));
|
||||||
setSpacing(4);
|
setSpacing(4);
|
||||||
getChildren().addAll(title, tips0, tips1, time, description);
|
getChildren().addAll(title, time);
|
||||||
}});
|
}});
|
||||||
setCenter(code);
|
setCenter(code);
|
||||||
}});
|
}});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.TitleLabel;
|
import com.imyeyu.fx.ui.components.TitleLabel;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
||||||
import com.imyeyu.fx.utils.BgFill;
|
import com.imyeyu.fx.utils.bg.BackgroundFillBuilder;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -29,9 +29,9 @@ public class Style extends AbstractPane {
|
|||||||
public Style() {
|
public Style() {
|
||||||
TitleLabel titleTimiFX = new TitleLabel("TimiFX");
|
TitleLabel titleTimiFX = new TitleLabel("TimiFX");
|
||||||
Label labelTimiFXDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
Label labelTimiFXDocument = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("document"));
|
||||||
XHyperlink timiFXDocument = new XHyperlink("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/TimiFX.html");
|
Hyperlink timiFXDocument = new Hyperlink("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/TimiFX.html");
|
||||||
Label labelTimiFXSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelTimiFXSource = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
XHyperlink timiFXSource = new XHyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/TimiFX.java");
|
Hyperlink timiFXSource = new Hyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/TimiFX.java");
|
||||||
Label labelTimiFXDescription = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description"));
|
Label labelTimiFXDescription = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("description"));
|
||||||
Label timiFXDescription = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.style.timifx"));
|
Label timiFXDescription = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.style.timifx"));
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public class Style extends AbstractPane {
|
|||||||
// 样式文件
|
// 样式文件
|
||||||
TitleLabel styleFile = new TitleLabel(TimiFXUI.MULTILINGUAL.text("fx.example.style.file"));
|
TitleLabel styleFile = new TitleLabel(TimiFXUI.MULTILINGUAL.text("fx.example.style.file"));
|
||||||
Label labelFile = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
Label labelFile = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("source"));
|
||||||
XHyperlink file = new XHyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/resources/timifx/style.css");
|
Hyperlink file = new Hyperlink("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/resources/timifx/style/style.css");
|
||||||
|
|
||||||
setCenter(new VBox() {{
|
setCenter(new VBox() {{
|
||||||
setSpacing(16);
|
setSpacing(16);
|
||||||
@@ -85,7 +85,7 @@ public class Style extends AbstractPane {
|
|||||||
getChildren().addAll(new BorderPane() {{
|
getChildren().addAll(new BorderPane() {{
|
||||||
setTop(titleTimiFX);
|
setTop(titleTimiFX);
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.key(), Column.valueFill());
|
||||||
setVgap(8);
|
setVgap(8);
|
||||||
setHgap(10);
|
setHgap(10);
|
||||||
setPadding(CONTENT_PADDING);
|
setPadding(CONTENT_PADDING);
|
||||||
@@ -98,7 +98,7 @@ public class Style extends AbstractPane {
|
|||||||
}}, new BorderPane() {{
|
}}, new BorderPane() {{
|
||||||
setTop(titleColor);
|
setTop(titleColor);
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.key(), Column.valueFill());
|
||||||
setVgap(8);
|
setVgap(8);
|
||||||
setHgap(10);
|
setHgap(10);
|
||||||
setPadding(CONTENT_PADDING);
|
setPadding(CONTENT_PADDING);
|
||||||
@@ -134,7 +134,7 @@ public class Style extends AbstractPane {
|
|||||||
}}, new BorderPane() {{
|
}}, new BorderPane() {{
|
||||||
setTop(styleFile);
|
setTop(styleFile);
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.key(), Column.valueFill());
|
||||||
setVgap(8);
|
setVgap(8);
|
||||||
setHgap(10);
|
setHgap(10);
|
||||||
setPadding(CONTENT_PADDING);
|
setPadding(CONTENT_PADDING);
|
||||||
@@ -152,7 +152,7 @@ public class Style extends AbstractPane {
|
|||||||
* @return 标签
|
* @return 标签
|
||||||
*/
|
*/
|
||||||
private Label colorLabel(String text, Paint color) {
|
private Label colorLabel(String text, Paint color) {
|
||||||
return colorLabel(text, new BgFill(color).build());
|
return colorLabel(text, BackgroundFillBuilder.solid(color).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages;
|
package com.imyeyu.fx.ui.examples.view.pages;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.ui.MinecraftFont;
|
import com.imyeyu.fx.ui.MinecraftFont;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextFlower;
|
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
import com.imyeyu.fx.ui.components.alert.AlertConfirm;
|
||||||
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
import com.imyeyu.fx.ui.components.alert.AlertTips;
|
||||||
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
import com.imyeyu.fx.ui.examples.TimiFXExamples;
|
||||||
@@ -12,13 +10,13 @@ import com.imyeyu.fx.ui.examples.component.AbstractPane;
|
|||||||
import com.imyeyu.fx.ui.examples.component.TimiVersionLabel;
|
import com.imyeyu.fx.ui.examples.component.TimiVersionLabel;
|
||||||
import com.imyeyu.fx.ui.examples.ctrl.Main;
|
import com.imyeyu.fx.ui.examples.ctrl.Main;
|
||||||
import com.imyeyu.fx.ui.examples.util.Resources;
|
import com.imyeyu.fx.ui.examples.util.Resources;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.FXApplication;
|
||||||
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import com.imyeyu.inject.annotation.PostConstruct;
|
import com.imyeyu.inject.annotation.PostConstruct;
|
||||||
import com.imyeyu.io.IO;
|
import com.imyeyu.io.IO;
|
||||||
import com.imyeyu.java.bean.Language;
|
import com.imyeyu.java.bean.Language;
|
||||||
import com.imyeyu.utils.OS;
|
import com.imyeyu.utils.OS;
|
||||||
import javafx.geometry.HPos;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
@@ -27,7 +25,6 @@ import javafx.scene.image.ImageView;
|
|||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.text.TextAlignment;
|
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,10 +49,6 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
title.setPadding(new Insets(8, 0, 8, 0));
|
title.setPadding(new Insets(8, 0, 8, 0));
|
||||||
MinecraftFont.css(title, MinecraftFont.X32);
|
MinecraftFont.css(title, MinecraftFont.X32);
|
||||||
|
|
||||||
// 文档和源码
|
|
||||||
TextFlower docSource = new TextFlower();
|
|
||||||
docSource.matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.top"));
|
|
||||||
docSource.setTextAlignment(TextAlignment.CENTER);
|
|
||||||
|
|
||||||
// 提示
|
// 提示
|
||||||
Label tips = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips"));
|
Label tips = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips"));
|
||||||
@@ -80,15 +73,9 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 版权
|
|
||||||
TextFlower license = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.license"));
|
|
||||||
license.setTextAlignment(TextAlignment.CENTER);
|
|
||||||
|
|
||||||
// 开发者
|
// 开发者
|
||||||
Label develop = new Label(TimiFXUI.MULTILINGUAL.text("developer.arg"));
|
Label develop = new Label(TimiFXUI.MULTILINGUAL.text("developer.arg"));
|
||||||
develop.setAlignment(Pos.CENTER);
|
develop.setAlignment(Pos.CENTER);
|
||||||
TextFlower blog = new TextFlower().matcher(TimiFXUI.MULTILINGUAL.text("blog"));
|
|
||||||
blog.setTextAlignment(TextAlignment.CENTER);
|
|
||||||
Label copyright = new Label(TimiFXUI.MULTILINGUAL.text("copyright"));
|
Label copyright = new Label(TimiFXUI.MULTILINGUAL.text("copyright"));
|
||||||
copyright.setAlignment(Pos.CENTER);
|
copyright.setAlignment(Pos.CENTER);
|
||||||
Label versionTimiFX = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version.timifx"));
|
Label versionTimiFX = new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.version.timifx"));
|
||||||
@@ -101,17 +88,13 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
setSpacing(20);
|
setSpacing(20);
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
setAlignment(Pos.TOP_CENTER);
|
setAlignment(Pos.TOP_CENTER);
|
||||||
getChildren().addAll(docSource, tips, new VBox() {{
|
getChildren().addAll(tips, new VBox() {{
|
||||||
setPadding(new Insets(40));
|
setPadding(new Insets(40));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips0")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips0")));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips1")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips1")));
|
||||||
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips2")));
|
getChildren().add(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips2")));
|
||||||
getChildren().add(new TextFlower() {{
|
|
||||||
setPadding(new Insets(40, 0, 0, 0));
|
|
||||||
matcher(TimiFXUI.MULTILINGUAL.text("fx.example.welcome.tips3"));
|
|
||||||
}});
|
|
||||||
getChildren().add(new GridPane() {{
|
getChildren().add(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.build(HPos.RIGHT), Column.VALUE);
|
getColumnConstraints().addAll(Column.builder().right().build(), Column.value());
|
||||||
setHgap(8);
|
setHgap(8);
|
||||||
setVgap(6);
|
setVgap(6);
|
||||||
setPadding(new Insets(12, 0, 4, 0));
|
setPadding(new Insets(12, 0, 4, 0));
|
||||||
@@ -131,7 +114,7 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
setAlignment(Pos.CENTER);
|
setAlignment(Pos.CENTER);
|
||||||
getChildren().addAll(TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("lang")), language);
|
getChildren().addAll(TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("lang")), language);
|
||||||
}});
|
}});
|
||||||
getChildren().addAll(versionTimiFX, version, develop, license, blog, copyright);
|
getChildren().addAll(versionTimiFX, version, develop, copyright);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +136,7 @@ public class Welcome extends AbstractPane implements OS.FileSystem {
|
|||||||
String jar = IO.getJarAbsolutePath(getClass());
|
String jar = IO.getJarAbsolutePath(getClass());
|
||||||
// 重启
|
// 重启
|
||||||
try {
|
try {
|
||||||
TimiFX.doRestart(TimiFXExamples.getInject().getBean(Main.class), jre + param + jar);
|
FXApplication.restart(TimiFXExamples.getInject().getBean(Main.class), jre + param + jar);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
AlertTips.error(this, TimiFXUI.MULTILINGUAL.text("tips.restart.error"));
|
AlertTips.error(this, TimiFXUI.MULTILINGUAL.text("tips.restart.error"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import com.imyeyu.fx.ui.examples.bean.Config;
|
|||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.animation.InterpolatorPane;
|
import com.imyeyu.fx.ui.examples.component.animation.InterpolatorPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import com.imyeyu.inject.annotation.PostConstruct;
|
import com.imyeyu.inject.annotation.PostConstruct;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
@@ -46,7 +46,7 @@ public class InterpolatorDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
// 重置
|
// 重置
|
||||||
Button reset = new Button(TimiFXUI.MULTILINGUAL.text("reset"));
|
Button reset = new Button(TimiFXUI.MULTILINGUAL.text("reset"));
|
||||||
reset.getStyleClass().add(CSS.BORDER_TRB);
|
reset.setBorder(Stroke.EX_LEFT);
|
||||||
|
|
||||||
// 持续时间
|
// 持续时间
|
||||||
duration = new Slider();
|
duration = new Slider();
|
||||||
@@ -102,7 +102,7 @@ public class InterpolatorDemo extends AbstractDemoPane {
|
|||||||
setPadding(new Insets(12, 0, 12, 0));
|
setPadding(new Insets(12, 0, 12, 0));
|
||||||
getChildren().addAll(panes);
|
getChildren().addAll(panes);
|
||||||
}});
|
}});
|
||||||
SmoothScroll.scrollPane(this);
|
SmoothScroll.pane.install(this);
|
||||||
}});
|
}});
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
|||||||
+21
-17
@@ -5,12 +5,11 @@ import com.imyeyu.fx.task.RunAsyncScheduled;
|
|||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.fx.utils.SmoothScroll;
|
import com.imyeyu.fx.utils.scroll.SmoothScroll;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import com.imyeyu.utils.Calc;
|
import com.imyeyu.utils.Calc;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.geometry.HPos;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
@@ -46,7 +45,7 @@ public class SmoothScrollDemo extends AbstractDemoPane {
|
|||||||
// 下拉框
|
// 下拉框
|
||||||
ComboBox<String> comboBoxDef = new ComboBox<>();
|
ComboBox<String> comboBoxDef = new ComboBox<>();
|
||||||
ComboBox<String> comboBox = new ComboBox<>();
|
ComboBox<String> comboBox = new ComboBox<>();
|
||||||
SmoothScroll.comboBox(comboBox);
|
SmoothScroll.virtual.install(comboBox);
|
||||||
|
|
||||||
// 滚动面板
|
// 滚动面板
|
||||||
VBox spDefVB = new VBox();
|
VBox spDefVB = new VBox();
|
||||||
@@ -55,37 +54,42 @@ public class SmoothScrollDemo extends AbstractDemoPane {
|
|||||||
ScrollPane scrollPane = new ScrollPane(spVB);
|
ScrollPane scrollPane = new ScrollPane(spVB);
|
||||||
scrollPaneDef.setBorder(Stroke.LT);
|
scrollPaneDef.setBorder(Stroke.LT);
|
||||||
scrollPane.setBorder(Stroke.LT);
|
scrollPane.setBorder(Stroke.LT);
|
||||||
SmoothScroll.scrollPane(scrollPane);
|
SmoothScroll.pane.install(scrollPane);
|
||||||
|
|
||||||
// 文本域
|
// 文本域
|
||||||
TextArea textAreaDef = new TextArea();
|
TextArea textAreaDef = new TextArea();
|
||||||
TextArea textArea = new TextArea();
|
TextArea textArea = new TextArea();
|
||||||
textAreaDef.getStyleClass().add(CSS.BORDER_LT);
|
textAreaDef.setBorder(Stroke.LT);
|
||||||
textArea.getStyleClass().add(CSS.BORDER_LT);
|
textArea.setBorder(Stroke.LT);
|
||||||
SmoothScroll.textarea(textArea);
|
SmoothScroll.text.install(textArea);
|
||||||
|
|
||||||
// 列表
|
// 列表
|
||||||
ListView<String> listViewDef = new ListView<>();
|
ListView<String> listViewDef = new ListView<>();
|
||||||
ListView<String> listView = new ListView<>();
|
ListView<String> listView = new ListView<>();
|
||||||
listViewDef.getStyleClass().add(CSS.BORDER_LT);
|
listViewDef.setBorder(Stroke.LT);
|
||||||
listView.getStyleClass().add(CSS.BORDER_LT);
|
listView.setBorder(Stroke.LT);
|
||||||
SmoothScroll.virtual(listView);
|
SmoothScroll.virtual.install(listView);
|
||||||
|
|
||||||
// 表格
|
// 表格
|
||||||
TableView<String> tableViewDef = new TableView<>();
|
TableView<String> tableViewDef = new TableView<>();
|
||||||
TableView<String> tableView = new TableView<>();
|
TableView<String> tableView = new TableView<>();
|
||||||
tableViewDef.getStyleClass().add(CSS.BORDER_LT);
|
tableViewDef.setBorder(Stroke.LT);
|
||||||
tableView.getStyleClass().add(CSS.BORDER_LT);
|
tableView.setBorder(Stroke.LT);
|
||||||
TableColumn<String, Object> col = new TableColumn<>("col");
|
TableColumn<String, Object> col = new TableColumn<>("col");
|
||||||
col.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue()));
|
col.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue()));
|
||||||
tableViewDef.getColumns().add(col);
|
tableViewDef.getColumns().add(col);
|
||||||
tableView.getColumns().add(col);
|
tableView.getColumns().add(col);
|
||||||
SmoothScroll.virtual(tableView);
|
SmoothScroll.virtual.install(tableView);
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
Column key = Column.build(HPos.RIGHT).percentWidth(10);
|
getColumnConstraints().addAll(
|
||||||
Column value = Column.build(HPos.CENTER).percentWidth(18).fill();
|
Column.builder().right().percentWidth(10).build(),
|
||||||
getColumnConstraints().addAll(key, value, value, value, value, value);
|
Column.builder().center().percentWidth(18).fill().build(),
|
||||||
|
Column.builder().center().percentWidth(18).fill().build(),
|
||||||
|
Column.builder().center().percentWidth(18).fill().build(),
|
||||||
|
Column.builder().center().percentWidth(18).fill().build(),
|
||||||
|
Column.builder().center().percentWidth(18).fill().build()
|
||||||
|
);
|
||||||
|
|
||||||
add(new StackPane() {{
|
add(new StackPane() {{
|
||||||
setBorder(Stroke.TOP);
|
setBorder(Stroke.TOP);
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
|
||||||
import com.imyeyu.fx.ui.components.CheckBoxPicker;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
|
||||||
import com.imyeyu.inject.annotation.Component;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.layout.FlowPane;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多选框选择器
|
|
||||||
*
|
|
||||||
* @author 夜雨
|
|
||||||
* @since 2022-08-29 15:27
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class CheckBoxPickerDemo extends AbstractDemoPane {
|
|
||||||
|
|
||||||
public CheckBoxPickerDemo() {
|
|
||||||
title.setText(SidebarItem.CHECK_BOX_PICKER.getText());
|
|
||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/CheckBoxPicker.html");
|
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/CheckBoxPicker.java");
|
|
||||||
|
|
||||||
// 选择器
|
|
||||||
CheckBoxPicker<String> picker = new CheckBoxPicker<>();
|
|
||||||
picker.setPrefWidth(390);
|
|
||||||
picker.getSelectedItems().addListener((ListChangeListener<String>) c -> {
|
|
||||||
List<String> items = picker.getSelectedItems();
|
|
||||||
picker.clear();
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
|
||||||
picker.appendText(items.get(i));
|
|
||||||
if (i < items.size() - 1) {
|
|
||||||
picker.appendText(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setCenter(new FlowPane() {{
|
|
||||||
setPadding(new Insets(20));
|
|
||||||
getChildren().add(picker);
|
|
||||||
}});
|
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
picker.getItems().add(TimiFXUI.MULTILINGUAL.text("fx.example.check_box_picker.item"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -3,7 +3,7 @@ package com.imyeyu.fx.ui.examples.view.pages.component;
|
|||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
@@ -63,7 +63,7 @@ public class EditableTableCellDemo extends AbstractDemoPane {
|
|||||||
tfxCol.prefWidthProperty().bind(tfx.widthProperty().subtract(50));
|
tfxCol.prefWidthProperty().bind(tfx.widthProperty().subtract(50));
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.VALUE_FILL, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.valueFill(), Column.valueFill());
|
||||||
setVgap(6);
|
setVgap(6);
|
||||||
setHgap(20);
|
setHgap(20);
|
||||||
setPadding(new Insets(32));
|
setPadding(new Insets(32));
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import com.imyeyu.fx.ui.TimiFXUI;
|
|||||||
import com.imyeyu.fx.ui.components.FileTreeView;
|
import com.imyeyu.fx.ui.components.FileTreeView;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.fx.utils.Row;
|
import com.imyeyu.fx.utils.grid.Row;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@@ -57,8 +57,8 @@ public class FileTreeViewDemo extends AbstractDemoPane {
|
|||||||
hide.setShowHide(true);
|
hide.setShowHide(true);
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.VALUE_FILL, Column.VALUE_FILL, Column.VALUE_FILL, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.valueFill(), Column.valueFill(), Column.valueFill(), Column.valueFill());
|
||||||
getRowConstraints().addAll(Row.build(), Row.build().alwaysPriority());
|
getRowConstraints().addAll(Row.builder().build(), Row.builder().alwaysPriority().build());
|
||||||
setVgap(5);
|
setVgap(5);
|
||||||
setPadding(new Insets(32));
|
setPadding(new Insets(32));
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.ProgressSlider;
|
import com.imyeyu.fx.ui.components.FilledSlider;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
@@ -10,21 +10,21 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.FlowPane;
|
import javafx.scene.layout.FlowPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拖拽进度组件
|
* 填充轨道滑动条示例
|
||||||
*
|
*
|
||||||
* @author 夜雨
|
* @author 夜雨
|
||||||
* @since 2022-08-30 09:36
|
* @since 2022-08-30 09:36
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class ProgressSliderDemo extends AbstractDemoPane {
|
public class FilledSliderDemo extends AbstractDemoPane {
|
||||||
|
|
||||||
public ProgressSliderDemo() {
|
public FilledSliderDemo() {
|
||||||
title.setText(SidebarItem.PROGRESS_SLIDER.getText());
|
title.setText(SidebarItem.FILLED_SLIDER.getText());
|
||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/ProgressSlider.html");
|
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/FilledSlider.html");
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/ProgressSlider.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/FilledSlider.java");
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
ProgressSlider slider = new ProgressSlider();
|
FilledSlider slider = new FilledSlider();
|
||||||
slider.setPrefWidth(360);
|
slider.setPrefWidth(360);
|
||||||
slider.setValue(.5);
|
slider.setValue(.5);
|
||||||
|
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.IconButton;
|
import com.imyeyu.fx.ui.components.IconButton;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,16 +27,16 @@ public class IconButtonDemo extends AbstractDemoPane {
|
|||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconButton.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconButton.java");
|
||||||
|
|
||||||
// 一般
|
// 一般
|
||||||
IconButton commonly = new IconButton(TimiFXUI.MULTILINGUAL.text("fx.example.icon_button"), TimiFXIcon.fromName("HAMMER"));
|
IconButton commonly = new IconButton(TimiFXUI.MULTILINGUAL.text("fx.example.icon_button"), TimiFXIcon.get(TimiIcon.HAMMER));
|
||||||
|
|
||||||
// 按钮背景
|
// 按钮背景
|
||||||
IconButton commonlyWithBG = new IconButton(TimiFXUI.MULTILINGUAL.text("fx.example.icon_button"), TimiFXIcon.fromName("HAMMER")).withBackground();
|
IconButton commonlyWithBG = new IconButton(TimiFXUI.MULTILINGUAL.text("fx.example.icon_button"), TimiFXIcon.get(TimiIcon.HAMMER)).withBackground();
|
||||||
|
|
||||||
// 无文本
|
// 无文本
|
||||||
IconButton notText = new IconButton(TimiFXIcon.fromName("HAMMER"));
|
IconButton notText = new IconButton(TimiFXIcon.get(TimiIcon.HAMMER));
|
||||||
|
|
||||||
// 无文本按钮背景
|
// 无文本按钮背景
|
||||||
IconButton notTextWithBG = new IconButton(TimiFXIcon.fromName("HAMMER")).withBackground();
|
IconButton notTextWithBG = new IconButton(TimiFXIcon.get(TimiIcon.HAMMER)).withBackground();
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
setVgap(4);
|
setVgap(4);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
|
import com.imyeyu.fx.ui.components.Hyperlink;
|
||||||
import com.imyeyu.fx.ui.components.IconPicker;
|
import com.imyeyu.fx.ui.components.IconPicker;
|
||||||
import com.imyeyu.fx.ui.components.XHyperlink;
|
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
@@ -26,7 +26,7 @@ public class IconPickerDemo extends AbstractDemoPane {
|
|||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconPicker.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/IconPicker.java");
|
||||||
|
|
||||||
// 图标主页
|
// 图标主页
|
||||||
XHyperlink index = new XHyperlink("https://www.imyeyu.net/article/public/aid119.html");
|
Hyperlink index = new Hyperlink("https://www.imyeyu.net/article/public/aid119.html");
|
||||||
|
|
||||||
if (getTop() instanceof VBox top) {
|
if (getTop() instanceof VBox top) {
|
||||||
top.getChildren().add(new TextFlow() {{
|
top.getChildren().add(new TextFlow() {{
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.Navigation;
|
import com.imyeyu.fx.ui.components.navigation.Navigation;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationGroup;
|
||||||
|
import com.imyeyu.fx.ui.components.navigation.NavigationItem;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.fx.utils.Row;
|
import com.imyeyu.fx.utils.grid.Row;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,42 +33,61 @@ public class NavigationDemo extends AbstractDemoPane {
|
|||||||
Label labelCommonly = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("commonly"));
|
Label labelCommonly = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("commonly"));
|
||||||
labelCommonly.setAlignment(Pos.CENTER);
|
labelCommonly.setAlignment(Pos.CENTER);
|
||||||
Navigation commonly = new Navigation();
|
Navigation commonly = new Navigation();
|
||||||
commonly.add(new ToggleButton("item 0"));
|
commonly.setPrefWidth(240);
|
||||||
commonly.add(new ToggleButton("item 1"));
|
commonly.add(new NavigationItem("item 0"));
|
||||||
commonly.add(new ToggleButton("item 2"));
|
commonly.add(new NavigationItem("item 1"));
|
||||||
|
commonly.add(new NavigationItem("item 2"));
|
||||||
|
|
||||||
// 二级
|
// 二级
|
||||||
Label labelSecond = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"));
|
Label labelSecond = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"));
|
||||||
labelSecond.setAlignment(Pos.CENTER);
|
labelSecond.setAlignment(Pos.CENTER);
|
||||||
Navigation second = new Navigation();
|
Navigation second = new Navigation();
|
||||||
second.add(new ToggleButton("item 0"));
|
second.add(new NavigationItem("item 0"));
|
||||||
second.add(new ToggleButton("item 1"));
|
second.add(new NavigationItem("item 1"));
|
||||||
second.add(new ToggleButton("item 2"));
|
second.add(new NavigationItem("item 2"));
|
||||||
second.addGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
second.add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1")));
|
||||||
|
|
||||||
// 默认展开
|
// 默认展开
|
||||||
Label labelExpanded = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.expanded"));
|
Label labelExpanded = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.expanded"));
|
||||||
labelExpanded.setAlignment(Pos.CENTER);
|
labelExpanded.setAlignment(Pos.CENTER);
|
||||||
Navigation expanded = new Navigation();
|
Navigation expanded = new Navigation();
|
||||||
expanded.add(new ToggleButton("item 0"));
|
expanded.add(new NavigationItem("item 0"));
|
||||||
expanded.add(new ToggleButton("item 1"));
|
expanded.add(new NavigationItem("item 1"));
|
||||||
expanded.add(new ToggleButton("item 2"));
|
expanded.add(new NavigationItem("item 2"));
|
||||||
expanded.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
expanded.add(new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1")));
|
||||||
|
|
||||||
// 多个二级
|
// 三级
|
||||||
Label labelMulti = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"));
|
Label labelMulti = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"));
|
||||||
labelMulti.setAlignment(Pos.CENTER);
|
labelMulti.setAlignment(Pos.CENTER);
|
||||||
Navigation multi = new Navigation();
|
Navigation multi = new Navigation();
|
||||||
multi.add(new ToggleButton("item 0"));
|
multi.add(new NavigationItem("item 0"));
|
||||||
multi.add(new ToggleButton("item 1"));
|
multi.add(new NavigationItem("item 1"));
|
||||||
multi.add(new ToggleButton("item 2"));
|
multi.add(new NavigationItem("item 2"));
|
||||||
multi.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
multi.add(
|
||||||
multi.addExpandedGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"), new ToggleButton("item 0"), new ToggleButton("item 1"));
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(
|
||||||
|
new NavigationItem("item 0"),
|
||||||
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.multi"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1"))
|
||||||
|
),
|
||||||
|
new NavigationGroup(TimiFXUI.MULTILINGUAL.text("fx.example.navigation.second"))
|
||||||
|
.expanded(true)
|
||||||
|
.add(new NavigationItem("item 0"), new NavigationItem("item 1"))
|
||||||
|
);
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
Column col = Column.build().width(120);
|
getColumnConstraints().addAll(
|
||||||
getColumnConstraints().addAll(col, col, col, col);
|
Column.builder().width(220).build(),
|
||||||
getRowConstraints().addAll(Row.build(), Row.build().alwaysPriority());
|
Column.builder().width(220).build(),
|
||||||
|
Column.builder().width(220).build(),
|
||||||
|
Column.builder().width(220).build()
|
||||||
|
);
|
||||||
|
getRowConstraints().addAll(Row.builder().build(), Row.builder().alwaysPriority().build());
|
||||||
setVgap(5);
|
setVgap(5);
|
||||||
setHgap(5);
|
setHgap(5);
|
||||||
setPadding(new Insets(32));
|
setPadding(new Insets(32));
|
||||||
|
|||||||
+3
-3
@@ -5,7 +5,7 @@ import com.imyeyu.fx.ui.components.TextAreaEditor;
|
|||||||
import com.imyeyu.fx.ui.components.TextAreaEditorField;
|
import com.imyeyu.fx.ui.components.TextAreaEditorField;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -33,14 +33,14 @@ public class TextAreaEditorDemo extends AbstractDemoPane {
|
|||||||
field.setTitle("TextAreaEditorField");
|
field.setTitle("TextAreaEditorField");
|
||||||
|
|
||||||
TextAreaEditor editor = new TextAreaEditor();
|
TextAreaEditor editor = new TextAreaEditor();
|
||||||
editor.getStyleClass().add(CSS.BORDER_L);
|
editor.setBorder(Stroke.LEFT);
|
||||||
|
|
||||||
setCenter(new BorderPane() {{
|
setCenter(new BorderPane() {{
|
||||||
setBorder(Stroke.TOP);
|
setBorder(Stroke.TOP);
|
||||||
setLeft(new BorderPane() {{
|
setLeft(new BorderPane() {{
|
||||||
setPadding(new Insets(12, 20, 12, 20));
|
setPadding(new Insets(12, 20, 12, 20));
|
||||||
setTop(new GridPane() {{
|
setTop(new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.KEY, Column.VALUE_FILL);
|
getColumnConstraints().addAll(Column.key(), Column.valueFill());
|
||||||
setVgap(8);
|
setVgap(8);
|
||||||
setHgap(10);
|
setHgap(10);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.ToggleIcon;
|
import com.imyeyu.fx.ui.components.ToggleIcon;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
@@ -27,16 +28,18 @@ public class ToggleIconDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
// 默认
|
// 默认
|
||||||
Label labelDef = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("default"));
|
Label labelDef = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("default"));
|
||||||
ToggleIcon def = new ToggleIcon(TimiFXIcon.fromName("ARROW_0_W"));
|
ToggleIcon def = new ToggleIcon(TimiFXIcon.get(TimiIcon.ARROW_0_W));
|
||||||
|
|
||||||
// 跟随状态变换
|
// 跟随状态变换
|
||||||
Label labelDiff = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.toggle_icon.diff"));
|
Label labelDiff = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.toggle_icon.diff"));
|
||||||
ToggleIcon diff = new ToggleIcon(TimiFXIcon.fromName("ARROW_0_W"), TimiFXIcon.fromName("ARROW_0_E"));
|
ToggleIcon diff = new ToggleIcon(TimiFXIcon.get(TimiIcon.ARROW_0_W), TimiFXIcon.get(TimiIcon.ARROW_0_E));
|
||||||
|
|
||||||
// 按钮背景
|
// 按钮背景
|
||||||
Label labelWithBG = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.toggle_icon.with_bg"));
|
Label labelWithBG = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.toggle_icon.with_bg"));
|
||||||
ToggleIcon withBG = new ToggleIcon(TimiFXIcon.fromName("ARROW_0_W")).withBackground();
|
ToggleIcon withBG = new ToggleIcon(TimiFXIcon.get(TimiIcon.ARROW_0_W)).withBackground();
|
||||||
ToggleIcon withBGDiff = new ToggleIcon(TimiFXIcon.fromName("ARROW_0_W"), TimiFXIcon.fromName("ARROW_0_E")).withBackground();
|
withBG.setBorder(Stroke.DEFAULT);
|
||||||
|
ToggleIcon withBGDiff = new ToggleIcon(TimiFXIcon.get(TimiIcon.ARROW_0_W), TimiFXIcon.get(TimiIcon.ARROW_0_E)).withBackground();
|
||||||
|
withBGDiff.setBorder(Stroke.DEFAULT);
|
||||||
|
|
||||||
setCenter(new GridPane() {{
|
setCenter(new GridPane() {{
|
||||||
setHgap(5);
|
setHgap(5);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.XPagination;
|
import com.imyeyu.fx.ui.components.Pagination;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.Column;
|
import com.imyeyu.fx.utils.grid.Column;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -26,7 +26,7 @@ public class XPaginationDemo extends AbstractDemoPane {
|
|||||||
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/XPagination.html");
|
document.sync("https://doc.imyeyu.net/timi-fx/net/imyeyu/timifx/component/XPagination.html");
|
||||||
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/XPagination.java");
|
source.sync("https://git.imyeyu.net/Timi/timi-fx/src/master/src/main/java/net/imyeyu/timifx/component/XPagination.java");
|
||||||
|
|
||||||
XPagination pagination = new XPagination();
|
Pagination pagination = new Pagination();
|
||||||
|
|
||||||
// 总数
|
// 总数
|
||||||
Label total = new Label();
|
Label total = new Label();
|
||||||
@@ -51,7 +51,7 @@ public class XPaginationDemo extends AbstractDemoPane {
|
|||||||
setCenter(new VBox() {{
|
setCenter(new VBox() {{
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
getChildren().addAll(pagination, new GridPane() {{
|
getChildren().addAll(pagination, new GridPane() {{
|
||||||
getColumnConstraints().addAll(Column.build(), Column.build().width(40));
|
getColumnConstraints().addAll(Column.builder().build(), Column.builder().width(40).build());
|
||||||
setHgap(10);
|
setHgap(10);
|
||||||
setVgap(8);
|
setVgap(8);
|
||||||
setPadding(new Insets(20 , 0, 0, 0));
|
setPadding(new Insets(20 , 0, 0, 0));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.component;
|
package com.imyeyu.fx.ui.examples.view.pages.component;
|
||||||
|
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.XTabPane;
|
import com.imyeyu.fx.ui.components.TabPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
@@ -10,8 +10,6 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签面板
|
* 标签面板
|
||||||
*
|
*
|
||||||
@@ -29,17 +27,15 @@ public class XTabPaneDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
Button add = new Button(TimiFXUI.MULTILINGUAL.text("add"));
|
Button add = new Button(TimiFXUI.MULTILINGUAL.text("add"));
|
||||||
|
|
||||||
XTabPane tabPane = new XTabPane();
|
TabPane tabPane = new TabPane();
|
||||||
|
tabPane.setTabClosingPolicy(javafx.scene.control.TabPane.TabClosingPolicy.ALL_TABS);
|
||||||
|
|
||||||
setCenter(new BorderPane() {{
|
setCenter(new BorderPane() {{
|
||||||
setMargin(add, new Insets(0, 0, 20, 0));
|
setMargin(add, new Insets(0, 0, 20, 0));
|
||||||
setPadding(new Insets(20));
|
setPadding(new Insets(20));
|
||||||
setTop(add);
|
setTop(add);
|
||||||
setCenter(tabPane);
|
setBottom(tabPane);
|
||||||
}});
|
}});
|
||||||
|
add.setOnAction(e -> tabPane.getTabs().add(new Tab("test顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶")));
|
||||||
add.setOnAction(e -> tabPane.getAdd().fire());
|
|
||||||
tabPane.getAdd().setOnAction(e -> tabPane.getTabs().add(new Tab(UUID.randomUUID().toString().substring(0, 8))));
|
|
||||||
tabPane.getAdd().fire();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import com.imyeyu.fx.ui.TimiFXUI;
|
|||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.BorderStroke;
|
import com.imyeyu.fx.utils.BorderBuilder;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.geometry.Orientation;
|
import javafx.geometry.Orientation;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
@@ -26,7 +26,7 @@ public class DraggableNodeDemo extends AbstractDemoPane {
|
|||||||
tips.setText(TimiFXUI.MULTILINGUAL.text("fx.example.draggable_node.tips"));
|
tips.setText(TimiFXUI.MULTILINGUAL.text("fx.example.draggable_node.tips"));
|
||||||
|
|
||||||
TextAreaEditor demo = new TextAreaEditor();
|
TextAreaEditor demo = new TextAreaEditor();
|
||||||
demo.getStyleClass().add(CSS.BORDER_T);
|
demo.setBorder(Stroke.TOP);
|
||||||
demo.setEditable(false);
|
demo.setEditable(false);
|
||||||
demo.setText("""
|
demo.setText("""
|
||||||
StackPane box = new StackPane();
|
StackPane box = new StackPane();
|
||||||
@@ -48,7 +48,7 @@ draggable.maxYProperty().bind(box.heightProperty().multiply(.5).subtract(pane.he
|
|||||||
StackPane box = new StackPane();
|
StackPane box = new StackPane();
|
||||||
|
|
||||||
StackPane pane = new StackPane(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.drag_me")));
|
StackPane pane = new StackPane(new Label(TimiFXUI.MULTILINGUAL.text("fx.example.drag_me")));
|
||||||
pane.setBorder(new BorderStroke(Colorful.FOCUSED_DEFAULT).width(2).build());
|
pane.setBorder(BorderBuilder.solid(Colorful.FOCUSED_DEFAULT).width(2).build());
|
||||||
pane.setMaxSize(200, 40);
|
pane.setMaxSize(200, 40);
|
||||||
pane.setEffect(Shadow.POPUP);
|
pane.setEffect(Shadow.POPUP);
|
||||||
pane.setBackground(BG.WHITE);
|
pane.setBackground(BG.WHITE);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import com.imyeyu.fx.ui.TimiFXUI;
|
|||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.utils.BorderStroke;
|
import com.imyeyu.fx.utils.BorderBuilder;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.inject.annotation.Component;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
@@ -33,7 +33,7 @@ public class DraggableWindowDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
popup = new Popup();
|
popup = new Popup();
|
||||||
popup.getContent().add(new BorderPane() {{
|
popup.getContent().add(new BorderPane() {{
|
||||||
setBorder(new BorderStroke(Colorful.RED).width(2).build());
|
setBorder(BorderBuilder.solid(Colorful.RED).width(2).build());
|
||||||
setBackground(BG.WHITE);
|
setBackground(BG.WHITE);
|
||||||
setTop(new StackPane() {{
|
setTop(new StackPane() {{
|
||||||
setBorder(Stroke.BOTTOM);
|
setBorder(Stroke.BOTTOM);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.imyeyu.fx.ui.examples.view.pages.other;
|
package com.imyeyu.fx.ui.examples.view.pages.other;
|
||||||
|
|
||||||
import com.imyeyu.fx.TimiFX;
|
|
||||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||||
|
import com.imyeyu.fx.icon.TimiIcon;
|
||||||
import com.imyeyu.fx.ui.TimiFXUI;
|
import com.imyeyu.fx.ui.TimiFXUI;
|
||||||
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
import com.imyeyu.fx.ui.components.TextAreaEditor;
|
||||||
import com.imyeyu.fx.ui.components.TrayFX;
|
import com.imyeyu.fx.ui.components.TrayFX;
|
||||||
@@ -9,9 +9,8 @@ import com.imyeyu.fx.ui.components.popup.PopupTipsService;
|
|||||||
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
import com.imyeyu.fx.ui.examples.component.AbstractDemoPane;
|
||||||
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
import com.imyeyu.fx.ui.examples.component.sidebar.SidebarItem;
|
||||||
import com.imyeyu.fx.ui.examples.ctrl.Main;
|
import com.imyeyu.fx.ui.examples.ctrl.Main;
|
||||||
import com.imyeyu.inject.annotation.Component;
|
import com.imyeyu.fx.utils.Windows;
|
||||||
import com.imyeyu.inject.annotation.PostConstruct;
|
import com.imyeyu.inject.annotation.PostConstruct;
|
||||||
import javafx.stage.Stage;
|
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.VPos;
|
import javafx.geometry.VPos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
@@ -21,6 +20,7 @@ import javafx.scene.control.MenuItem;
|
|||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import java.awt.TrayIcon;
|
import java.awt.TrayIcon;
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ public class TrayFXDemo extends AbstractDemoPane {
|
|||||||
|
|
||||||
show = new Button(TimiFXUI.MULTILINGUAL.text("show"));
|
show = new Button(TimiFXUI.MULTILINGUAL.text("show"));
|
||||||
hide = new Button(TimiFXUI.MULTILINGUAL.text("remove"));
|
hide = new Button(TimiFXUI.MULTILINGUAL.text("remove"));
|
||||||
hide.getStyleClass().add(CSS.BORDER_TRB);
|
hide.setBorder(Stroke.EX_LEFT);
|
||||||
|
|
||||||
Label labelSendMsg = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.tray.send_msg"));
|
Label labelSendMsg = TimiFXUI.label(TimiFXUI.MULTILINGUAL.text("fx.example.tray.send_msg"));
|
||||||
|
|
||||||
@@ -108,9 +108,9 @@ public class TrayFXDemo extends AbstractDemoPane {
|
|||||||
hide.disableProperty().bind(trayFX.showingProperty().not());
|
hide.disableProperty().bind(trayFX.showingProperty().not());
|
||||||
|
|
||||||
MenuItem show = new MenuItem(TimiFXUI.MULTILINGUAL.text("show"));
|
MenuItem show = new MenuItem(TimiFXUI.MULTILINGUAL.text("show"));
|
||||||
MenuItem exit = new MenuItem(TimiFXUI.MULTILINGUAL.text("exit"), TimiFXIcon.fromName("FAIL", Colorful.RED));
|
MenuItem exit = new MenuItem(TimiFXUI.MULTILINGUAL.text("exit"), TimiFXIcon.get(TimiIcon.FAIL, Colorful.RED));
|
||||||
|
|
||||||
show.setOnAction(e -> TimiFX.requestTop(stage));
|
show.setOnAction(e -> Windows.requestTop(stage));
|
||||||
exit.setOnAction(e -> main.stop());
|
exit.setOnAction(e -> main.stop());
|
||||||
|
|
||||||
trayFX.addMenu(0, show, TimiFXUI.sep(), exit);
|
trayFX.addMenu(0, show, TimiFXUI.sep(), exit);
|
||||||
|
|||||||
Reference in New Issue
Block a user