244 lines
6.1 KiB
Java
244 lines
6.1 KiB
Java
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 java.util.List;
|
||
|
||
/**
|
||
* 纵向导航组件,可实现二级导航,折叠导航
|
||
*
|
||
* @author 夜雨
|
||
* @since 2022-02-17 00:11
|
||
*/
|
||
public class Navigation extends ScrollPane implements TimiFXUI {
|
||
|
||
/** 导航列表项 */
|
||
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> childrens = root.getChildren();
|
||
|
||
// 响应 TimiFXUI
|
||
items.addListener((ListChangeListener<ToggleButton>) c -> {
|
||
while (c.next()) {
|
||
if (c.wasAdded()) {
|
||
// 添加
|
||
List<? extends ToggleButton> list = c.getAddedSubList();
|
||
for (int i = 0; i < list.size(); i++) {
|
||
list.get(i).setMaxWidth(Double.MAX_VALUE);
|
||
list.get(i).getStyleClass().setAll(CSS.MINECRAFT, "navigation-button");
|
||
list.get(i).addEventFilter(MouseEvent.MOUSE_PRESSED, TimiFX.EVENT_CONSUME_TG_BTN);
|
||
|
||
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) {
|
||
// 存在所属组
|
||
if (!childrens.contains(pane)) {
|
||
// 未添加组
|
||
childrens.add(pane);
|
||
}
|
||
if (pane.getContent() instanceof VBox box) {
|
||
box.getChildren().add(list.get(i));
|
||
}
|
||
} else {
|
||
// 单独项
|
||
if (!childrens.isEmpty()) {
|
||
if (childrens.get(childrens.size() - 1) instanceof TitledPane) {
|
||
// 上一项是组导航,添加上边框
|
||
list.get(i).getStyleClass().add("after-group");
|
||
}
|
||
}
|
||
childrens.add(list.get(i));
|
||
}
|
||
// 归组
|
||
group.getToggles().add(list.get(i));
|
||
}
|
||
return;
|
||
}
|
||
if (c.wasRemoved()) {
|
||
// 移除
|
||
List<? extends ToggleButton> list = c.getRemoved();
|
||
for (int i = 0; i < list.size(); i++) {
|
||
if (list.get(i).getProperties().get("OWNER") instanceof TitledPane pane) {
|
||
// 存在所属组
|
||
if (pane.getContent() instanceof VBox box) {
|
||
box.getChildren().remove(list.get(i));
|
||
if (box.getChildren().isEmpty()) {
|
||
// 该组已没有列表项
|
||
childrens.remove(box);
|
||
}
|
||
}
|
||
} else {
|
||
// 单独项
|
||
childrens.remove(list.get(i));
|
||
}
|
||
// 从组移除
|
||
group.getToggles().remove(list.get(i));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 添加导航按钮
|
||
*
|
||
* @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 (int i = 0; i < buttons.length; i++) {
|
||
buttons[i].getProperties().put("OWNER", pane);
|
||
items.add(buttons[i]);
|
||
}
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* 获取导航数据列表
|
||
*
|
||
* @return 导航数据列表
|
||
*/
|
||
public ObservableList<ToggleButton> getItems() {
|
||
return items;
|
||
}
|
||
}
|