Initial project
This commit is contained in:
243
src/main/java/com/imyeyu/fx/ui/components/Navigation.java
Normal file
243
src/main/java/com/imyeyu/fx/ui/components/Navigation.java
Normal file
@ -0,0 +1,243 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user