From 6949ff4cfd9f01f5cd841070e113948319db5555 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Fri, 9 Jan 2026 21:07:55 +0000 Subject: [PATCH 01/15] FVKB-129: Add the ability to increase row span --- .../view/control/GridBaseControl.java | 11 +++++++++ .../GridNodePropertiesPane.java | 24 ++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/GridBaseControl.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/GridBaseControl.java index e00ff1892..10420c275 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/GridBaseControl.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/GridBaseControl.java @@ -45,4 +45,15 @@ protected void invalidated() { public int getColumnSpan() { return columnSpan.get(); } public IntegerProperty columnSpanProperty() { return columnSpan; } public void setColumnSpan(int index) { columnSpan.set(index); } + + // -- row span + private final IntegerProperty rowSpan = new SimpleIntegerProperty(1){ + @Override + protected void invalidated() { + GridPane.setRowSpan(GridBaseControl.this, get()); + } + }; + public int getRowSpan() { return rowSpan.get(); } + public IntegerProperty rowSpanProperty() { return rowSpan; } + public void setRowSpan(int span) { this.rowSpan.set(span); } } \ No newline at end of file diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java index 0d254006a..9b896d6db 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java @@ -20,8 +20,10 @@ public class GridNodePropertiesPane extends ControlBa protected final ComboBox columnPositionCB = new ComboBox<>(); protected final ComboBox rowPositionCB = new ComboBox<>(); protected final ComboBox columnSpanCB = new ComboBox<>(); + protected final ComboBox rowSpanCB = new ComboBox<>(); protected ObjectProperty previousControlColumnSpanProperty; + protected ObjectProperty previousControlRowSpanProperty; protected Subscription columnIndexSubscription; protected Subscription rowIndexSubscription; @@ -61,7 +63,7 @@ public GridNodePropertiesPane() { GridPane.setHalignment(columnPositionLabel, HPos.RIGHT); positioningGridPane.add(columnPositionLabel, 0, 0); - // Column Position ComboBox + // - Column Position ComboBox columnPositionCB.setItems(FXCollections.observableArrayList(List.of(1, 2, 3))); columnPositionCB.setMaxWidth(Double.MAX_VALUE); positioningGridPane.add(columnPositionCB, 1, 0); @@ -71,7 +73,7 @@ public GridNodePropertiesPane() { GridPane.setHalignment(rowLabel, HPos.RIGHT); positioningGridPane.add(rowLabel, 0, 1); - // Row Position ComboBox + // - Row Position ComboBox rowPositionCB.setItems((FXCollections.observableArrayList(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))); rowPositionCB.setMaxWidth(Double.MAX_VALUE); positioningGridPane.add(rowPositionCB, 1, 1); @@ -81,11 +83,21 @@ public GridNodePropertiesPane() { GridPane.setHalignment(columnSpanLabel, HPos.RIGHT); positioningGridPane.add(columnSpanLabel, 0, 2); - // Column Span ComboBox + // - Column Span ComboBox columnSpanCB.setItems((FXCollections.observableArrayList(List.of(1, 2, 3)))); columnSpanCB.setMaxWidth(Double.MAX_VALUE); positioningGridPane.add(columnSpanCB, 1, 2); + // Row Span + Label rowSpanLabel = new Label("Row Span"); + GridPane.setHalignment(rowSpanLabel, HPos.RIGHT); + positioningGridPane.add(rowSpanLabel, 0, 3); + + // - Row Span ComboBox + rowSpanCB.setItems((FXCollections.observableArrayList(List.of(1, 2, 3)))); + rowSpanCB.setMaxWidth(Double.MAX_VALUE); + positioningGridPane.add(rowSpanCB, 1, 3); + } @Override @@ -93,7 +105,9 @@ protected void doInit(D control) { if (previouslyShownControl != null) { columnIndexSubscription.unsubscribe(); rowIndexSubscription.unsubscribe(); + columnSpanCB.valueProperty().unbindBidirectional(previousControlColumnSpanProperty); + rowSpanCB.valueProperty().unbindBidirectional(previousControlRowSpanProperty); } // Column Index @@ -113,5 +127,9 @@ protected void doInit(D control) { // Column Span previousControlColumnSpanProperty = control.columnSpanProperty().asObject(); columnSpanCB.valueProperty().bindBidirectional(previousControlColumnSpanProperty); + + // Row Span + previousControlRowSpanProperty = control.rowSpanProperty().asObject(); + rowSpanCB.valueProperty().bindBidirectional(previousControlRowSpanProperty); } } \ No newline at end of file From b65c7e88f59c27cca67bc94a59cc2cfeac8233aa Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Sat, 10 Jan 2026 18:53:11 +0000 Subject: [PATCH 02/15] Improve Field Column Span aesthetics and move styling 'code' to CSS --- .../view/skin/EditorGridPaneSkin.java | 21 +++++++++---------- .../kleditorapp/view/kl-editor-window.css | 17 +++++++++++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java index 49930de9e..04fe8f52f 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java @@ -31,6 +31,7 @@ public class EditorGridPaneSkin extends SkinBase { private static final int DRAG_LINE_WIDTH = 5; + private static final PseudoClass MOUSE_HOVER_WHILE_DRAGGING_PSEUDO_CLASS = PseudoClass.getPseudoClass("mouse-hover-dragging"); private final GridPane gridPane = new GridPane(); private final List gridTiles = new ArrayList<>(); @@ -185,8 +186,9 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rectWhileDragging.setManaged(false); rectWhileDragging.setMouseTransparent(true); - rectWhileDragging.setStroke(Color.TRANSPARENT); - rectWhileDragging.setFill(Color.TRANSPARENT); + rectWhileDragging.setVisible(false); + + rectWhileDragging.getStyleClass().add("rect-while-dragging"); // Rectangle (line) used to catch the actual drag to change column span Rectangle rightEdge = new Rectangle(); @@ -216,10 +218,9 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rightEdge.setOnMouseDragged(mouseEvent -> { double mouseX = rightEdge.localToParent(mouseEvent.getX(), 0).getX(); + rectWhileDragging.setVisible(true); rectWhileDragging.setWidth(mouseX - rectWhileDragging.getLayoutX()); - rectWhileDragging.setStroke(Color.web("#5dcf16")); - Bounds gridControlBounds = gridPane.localToParent(gridBaseControl.getBoundsInParent()); if (mouseX > gridControlBounds.getMaxX()) { // Dragging mouse to make Tile bigger @@ -228,32 +229,30 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) Optional optionalGridTile = getGridTile(gridBaseControl.getRowIndex(), gridBaseControl.getColumnIndex() + columnCount); if (optionalGridTile.isPresent()) { GridTile gridTile = optionalGridTile.get(); - - Bounds mouseHoverGridTileBounds = gridPane.localToParent(gridTile.getBoundsInParent()); - if (mouseX >= mouseHoverGridTileBounds.getCenterX()) { + Bounds gridTileBounds = gridPane.localToParent(gridTile.getBoundsInParent()); + if (mouseX >= gridTileBounds.getCenterX()) { currentMouseHoverGridTile = gridTile; mouseHoverGridTiles.add(currentMouseHoverGridTile); - currentMouseHoverGridTile.setStyle("-fx-background-color: #7ac257;"); - if (mouseX <= currentMouseHoverGridTile.getLayoutX() + mouseHoverGridTileBounds.getWidth()) { + if (mouseX <= currentMouseHoverGridTile.getLayoutX() + gridTileBounds.getWidth()) { break; // Found the Tile where the mouse is hover } } } else { break; } + ++columnCount; } } }); rightEdge.setOnMouseReleased(mouseEvent -> { - rectWhileDragging.setStroke(Color.TRANSPARENT); + rectWhileDragging.setVisible(false); if (currentMouseHoverGridTile == null) { return; } - int gridBaseControlColIndex = gridBaseControl.getColumnIndex(); int mouseHoverGridTileColIndex = currentMouseHoverGridTile.getColumnIndex(); gridBaseControl.setColumnSpan(mouseHoverGridTileColIndex - gridBaseControlColIndex + 1); diff --git a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css index 481ad944c..ba59a776f 100644 --- a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css +++ b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css @@ -97,6 +97,16 @@ * * ******************************************************************************/ +/******************************************************************************* + * EditorGridPane * + ******************************************************************************/ + +.editor-grid-pane > .rect-while-dragging { + -fx-stroke: #5dcf16; + -fx-fill: transparent; +} + + /******************************************************************************* * Section View * ******************************************************************************/ @@ -147,6 +157,10 @@ -fx-padding: 2px; } +.window .section-view .content > .editor-grid-pane > GridPane > .grid-tile:mouse-hover-dragging { + -fx-background-color: #ccc; +} + .window .section-view .content > .editor-grid-pane > GridPane > .grid-tile:empty { -fx-pref-height: 100px; } @@ -219,6 +233,9 @@ -fx-border-style: solid, solid; -fx-border-width: 1px, 1px; + -fx-background-color: white; + -fx-background-insets: 1px; + -fx-padding: 0 2px 0 2px; } From 6e2724d9e6a771825068dab99cc43aebc5c04f19 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Sat, 10 Jan 2026 23:36:17 +0000 Subject: [PATCH 03/15] Further refactor and clean code --- .../kleditorapp/view/skin/EditorGridPaneSkin.java | 15 +++++++-------- .../komet/kleditorapp/view/kl-editor-window.css | 3 +++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java index 04fe8f52f..4dd1ad93e 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java @@ -180,15 +180,12 @@ private void updateTiles() { private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) { // Rectangle that becomes visible when user is dragging and covers the Grid Control's bounds Rectangle rectWhileDragging = new Rectangle(); - - rectWhileDragging.setArcHeight(3); - rectWhileDragging.setArcWidth(3); + rectWhileDragging.getStyleClass().add("rect-while-dragging"); rectWhileDragging.setManaged(false); rectWhileDragging.setMouseTransparent(true); - rectWhileDragging.setVisible(false); - rectWhileDragging.getStyleClass().add("rect-while-dragging"); + rectWhileDragging.setVisible(false); // Rectangle (line) used to catch the actual drag to change column span Rectangle rightEdge = new Rectangle(); @@ -198,7 +195,11 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rightEdge.setFill(Color.TRANSPARENT); rightEdge.setStroke(Color.TRANSPARENT); + getChildren().add(rectWhileDragging); + getChildren().add(rightEdge); + gridBaseControl.boundsInParentProperty().subscribe(bounds -> { + // Update drag handles and drag visuals if control changes bounds Bounds grindControlBounds = gridPane.localToParent(bounds); rectWhileDragging.setLayoutX(grindControlBounds.getMinX()); rectWhileDragging.setLayoutY(grindControlBounds.getMinY()); @@ -211,10 +212,8 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rightEdge.setHeight(grindControlBounds.getHeight()); }); - getChildren().add(rectWhileDragging); - getChildren().add(rightEdge); + //===================== Setup mouse events on Right Edge ========================== - // Setup mouse events on Right Edge rightEdge.setOnMouseDragged(mouseEvent -> { double mouseX = rightEdge.localToParent(mouseEvent.getX(), 0).getX(); diff --git a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css index ba59a776f..0a58c1384 100644 --- a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css +++ b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css @@ -102,6 +102,9 @@ ******************************************************************************/ .editor-grid-pane > .rect-while-dragging { + -fx-arc-height: 3px; + -fx-arc-width: 3px; + -fx-stroke: #5dcf16; -fx-fill: transparent; } From da7ddfb9379a5347897c7a21de86dcc9e975e735 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Mon, 12 Jan 2026 12:44:28 +0000 Subject: [PATCH 04/15] FVKB-136: Add the ability to increase row span through drag and drop --- .../view/skin/EditorGridPaneSkin.java | 92 +++++++++++++++---- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java index 4dd1ad93e..1e5ba84eb 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java @@ -30,13 +30,12 @@ import java.util.Optional; public class EditorGridPaneSkin extends SkinBase { - private static final int DRAG_LINE_WIDTH = 5; + private static final int DRAG_LINE_THICKNESS = 5; private static final PseudoClass MOUSE_HOVER_WHILE_DRAGGING_PSEUDO_CLASS = PseudoClass.getPseudoClass("mouse-hover-dragging"); private final GridPane gridPane = new GridPane(); private final List gridTiles = new ArrayList<>(); - private final List mouseHoverGridTiles = new ArrayList<>(); private GridTile currentMouseHoverGridTile; /** @@ -187,7 +186,7 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rectWhileDragging.setVisible(false); - // Rectangle (line) used to catch the actual drag to change column span + // Rectangle (line) used to catch the actual drag to change Column Span Rectangle rightEdge = new Rectangle(); rightEdge.setManaged(false); @@ -195,21 +194,39 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) rightEdge.setFill(Color.TRANSPARENT); rightEdge.setStroke(Color.TRANSPARENT); - getChildren().add(rectWhileDragging); - getChildren().add(rightEdge); + // Rectangle (line) used to catch the actual drag to change Row Span + Rectangle bottomEdge = new Rectangle(); + bottomEdge.setManaged(false); + + bottomEdge.setCursor(Cursor.V_RESIZE); + bottomEdge.setFill(Color.TRANSPARENT); + bottomEdge.setStroke(Color.TRANSPARENT); + + // Add children to scene graph + getChildren().addAll( + rectWhileDragging, + rightEdge, + bottomEdge + ); gridBaseControl.boundsInParentProperty().subscribe(bounds -> { // Update drag handles and drag visuals if control changes bounds - Bounds grindControlBounds = gridPane.localToParent(bounds); - rectWhileDragging.setLayoutX(grindControlBounds.getMinX()); - rectWhileDragging.setLayoutY(grindControlBounds.getMinY()); - rectWhileDragging.setWidth(grindControlBounds.getWidth()); - rectWhileDragging.setHeight(grindControlBounds.getHeight()); - - rightEdge.setLayoutX(grindControlBounds.getMaxX() - DRAG_LINE_WIDTH); - rightEdge.setWidth(DRAG_LINE_WIDTH); - rightEdge.setLayoutY(grindControlBounds.getMinY()); - rightEdge.setHeight(grindControlBounds.getHeight()); + Bounds gridControlBounds = gridPane.localToParent(bounds); + + rectWhileDragging.setLayoutX(gridControlBounds.getMinX()); + rectWhileDragging.setLayoutY(gridControlBounds.getMinY()); + rectWhileDragging.setWidth(gridControlBounds.getWidth()); + rectWhileDragging.setHeight(gridControlBounds.getHeight()); + + rightEdge.setLayoutX(gridControlBounds.getMaxX() - DRAG_LINE_THICKNESS); + rightEdge.setWidth(DRAG_LINE_THICKNESS); + rightEdge.setLayoutY(gridControlBounds.getMinY()); + rightEdge.setHeight(gridControlBounds.getHeight()); + + bottomEdge.setLayoutX(gridControlBounds.getMinX()); + bottomEdge.setLayoutY(gridControlBounds.getMaxY() - DRAG_LINE_THICKNESS); + bottomEdge.setWidth(gridControlBounds.getWidth()); + bottomEdge.setHeight(DRAG_LINE_THICKNESS); }); //===================== Setup mouse events on Right Edge ========================== @@ -231,7 +248,6 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) Bounds gridTileBounds = gridPane.localToParent(gridTile.getBoundsInParent()); if (mouseX >= gridTileBounds.getCenterX()) { currentMouseHoverGridTile = gridTile; - mouseHoverGridTiles.add(currentMouseHoverGridTile); if (mouseX <= currentMouseHoverGridTile.getLayoutX() + gridTileBounds.getWidth()) { break; // Found the Tile where the mouse is hover } @@ -258,6 +274,50 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) currentMouseHoverGridTile = null; }); + + bottomEdge.setOnMouseDragged(mouseEvent -> { + double mouseY = bottomEdge.localToParent(0, mouseEvent.getY()).getY(); + + rectWhileDragging.setVisible(true); + rectWhileDragging.setHeight(mouseY - rectWhileDragging.getLayoutY()); + + Bounds gridControlBounds = gridPane.localToParent(gridBaseControl.getBoundsInParent()); + if (mouseY > gridControlBounds.getMaxY()) { + // Dragging mouse to make Tile bigger + int rowCount = 1; + while(true) { + Optional optionalGridTile = getGridTile(gridBaseControl.getRowIndex() + rowCount, gridBaseControl.getColumnIndex()); + if (optionalGridTile.isPresent()) { + GridTile gridTile = optionalGridTile.get(); + Bounds gridTileBounds = gridPane.localToParent(gridTile.getBoundsInParent()); + if (mouseY >= gridTileBounds.getCenterY()) { + currentMouseHoverGridTile = gridTile; + if (mouseY <= currentMouseHoverGridTile.getLayoutY() + gridTileBounds.getHeight()) { + break; // Found the Tile where the mouse is hover + } + } + } else { + break; + } + + ++rowCount; + } + } + }); + + bottomEdge.setOnMouseReleased(mouseEvent -> { + rectWhileDragging.setVisible(false); + + if (currentMouseHoverGridTile == null) { + return; + } + + int gridBaseControlRowIndex = gridBaseControl.getRowIndex(); + int mouseHoverGridTileRowIndex = currentMouseHoverGridTile.getRowIdex(); + gridBaseControl.setRowSpan(mouseHoverGridTileRowIndex - gridBaseControlRowIndex + 1); + + currentMouseHoverGridTile = null; + }); } /*************************************************************************** From b157446c16b0f66df42dbd1be902f6e0065bf4e0 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Thu, 15 Jan 2026 12:49:34 +0000 Subject: [PATCH 05/15] FVKB-145: Add the ability to toggle the Pattern title visibility --- .../view/KLEditorWindowController.java | 1 + .../view/control/PatternViewControl.java | 16 + .../propertiespane/PatternPropertiesPane.java | 18 +- .../editor/model/EditorPatternModel.java | 15 + .../komet/kview/controls/ToggleSwitch.java | 170 ++++++++++ .../controls/skin/FXToggleSwitchSkin.java | 320 ++++++++++++++++++ .../GenPurposeDetailsController.java | 2 + .../ikm/komet/kview/controls/toggleswitch.css | 53 +++ .../preferences/KLEditorPreferences.java | 4 + 9 files changed, 596 insertions(+), 3 deletions(-) create mode 100644 kview/src/main/java/dev/ikm/komet/kview/controls/ToggleSwitch.java create mode 100644 kview/src/main/java/dev/ikm/komet/kview/controls/skin/FXToggleSwitchSkin.java create mode 100644 kview/src/main/resources/dev/ikm/komet/kview/controls/toggleswitch.css diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java index 63fc7527e..a904d56b3 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java @@ -105,6 +105,7 @@ private void addPatternView(EditorSectionModel editorSectionModel, EditorPattern patternModelToView.put(patternModel, patternViewControl); patternViewControl.titleProperty().bind(patternModel.titleProperty()); + patternViewControl.titleVisibleProperty().bindBidirectional(patternModel.titleVisibleProperty()); patternViewControl.numberColumnsProperty().bindBidirectional(patternModel.numberColumnsProperty()); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternViewControl.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternViewControl.java index cba7839a8..da81eb477 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternViewControl.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternViewControl.java @@ -1,19 +1,24 @@ package dev.ikm.komet.kleditorapp.view.control; import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import javafx.css.PseudoClass; import javafx.scene.control.Label; import javafx.scene.layout.VBox; public class PatternViewControl extends GridBaseControl { + public static final PseudoClass TITLE_VISIBLE = PseudoClass.getPseudoClass("title-visible"); + public static final String DEFAULT_STYLE_CLASS = "pattern-view"; private final VBox patternContainer = new VBox(); @@ -82,6 +87,17 @@ protected void layoutChildren() { public StringProperty titleProperty() { return title; } public void setTitle(String title) { this.title.set(title); } + // -- title visible + private final BooleanProperty titleVisible = new SimpleBooleanProperty() { + @Override + protected void invalidated() { + pseudoClassStateChanged(TITLE_VISIBLE, get()); + } + }; + public boolean isTitleVisible() { return titleVisible.get(); } + public BooleanProperty titleVisibleProperty() { return titleVisible; } + public void setTitleVisible(boolean value) { titleVisible.setValue(value); } + // -- number columns private final IntegerProperty numberColumns = new SimpleIntegerProperty(1); public int getNumberColumns() { return numberColumns.get(); } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java index 8c4d1dfe6..ea8493931 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java @@ -1,7 +1,7 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; -import dev.ikm.komet.kleditorapp.view.ControlBasePropertiesPane; import dev.ikm.komet.kleditorapp.view.control.PatternViewControl; +import dev.ikm.komet.kview.controls.ToggleSwitch; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.geometry.HPos; @@ -23,6 +23,7 @@ public class PatternPropertiesPane extends GridNodePropertiesPane columnsComboBox = new ComboBox<>(); @@ -34,10 +35,18 @@ public PatternPropertiesPane() { titleContainer.getStyleClass().add("title-container"); titleContainer.setSpacing(4); - Label nameLabel = new Label("Title:"); + Label titleLabel = new Label("Title:"); titleTextField = new TextField(); - titleContainer.getChildren().addAll(nameLabel, titleTextField); + titleContainer.getChildren().addAll(titleLabel, titleTextField); + + // Visible + titleVisibleTSwitch = new ToggleSwitch(); + titleVisibleTSwitch.setText("Visible"); + titleVisibleTSwitch.setSelected(false); + titleVisibleTSwitch.getStyleClass().add("title-visible"); + + titleTextField.editableProperty().bind(titleVisibleTSwitch.selectedProperty()); // Separator Separator separator = new Separator(); @@ -88,6 +97,7 @@ public PatternPropertiesPane() { patternMainContainer.getChildren().addAll( titleContainer, + titleVisibleTSwitch, separator, gridTitleLabel, gridLayoutGridPane, @@ -109,9 +119,11 @@ protected void doInit(PatternViewControl control) { if (previouslyShownControl != null) { columnsComboBox.valueProperty().unbindBidirectional(previousControlColumnsObjProperty); + titleVisibleTSwitch.selectedProperty().unbindBidirectional(previouslyShownControl.titleVisibleProperty()); } titleTextField.setText(control.getTitle()); + titleVisibleTSwitch.selectedProperty().bindBidirectional(control.titleVisibleProperty()); // Columns ComboBox previousControlColumnsObjProperty = control.numberColumnsProperty().asObject(); diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java index 089772d2c..4f1ab7e60 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java @@ -1,5 +1,6 @@ package dev.ikm.komet.layout.editor.model; +import dev.ikm.komet.preferences.KLEditorPreferences; import dev.ikm.komet.preferences.KometPreferences; import dev.ikm.tinkar.coordinate.stamp.calculator.Latest; import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator; @@ -9,7 +10,9 @@ import dev.ikm.tinkar.entity.FieldDefinitionRecord; import dev.ikm.tinkar.entity.PatternVersionRecord; import dev.ikm.tinkar.terms.PatternFacade; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -28,6 +31,7 @@ import static dev.ikm.komet.preferences.KLEditorPreferences.GridLayoutKey.KL_GRID_NUMBER_COLUMNS; import static dev.ikm.komet.preferences.KLEditorPreferences.ListKey.PATTERN_LIST; +import static dev.ikm.komet.preferences.KLEditorPreferences.PatternKey.PATTERN_TITLE_VISIBLE; /** * Represents a Pattern. It has properties like the title of the Pattern, the fields inside it (EditorFieldModel instances), @@ -102,6 +106,7 @@ private static String patternFacadeToPrefsDirName(PatternFacade patternFacade) { private void loadPatternDetails(KometPreferences patternPreferences, ViewCalculator viewCalculator) { patternPreferences.getInt(KL_GRID_NUMBER_COLUMNS).ifPresent(this::setNumberColumns); + patternPreferences.getBoolean(PATTERN_TITLE_VISIBLE).ifPresent(this::setTitleVisible); loadGridNodeDetails(patternPreferences); for (EditorFieldModel fieldModel : getFields()) { @@ -134,8 +139,12 @@ public void save(KometPreferences sectionPreferences) { private void savePatternDetails(KometPreferences sectionPreferences) { KometPreferences patternPreferences = sectionPreferences.node(patternFacadeToPrefsDirName(patternFacade)); + // Grid patternPreferences.putInt(KL_GRID_NUMBER_COLUMNS, getNumberColumns()); + // title visible + patternPreferences.putBoolean(PATTERN_TITLE_VISIBLE, isTitleVisible()); + saveGridNodeDetails(patternPreferences); for (EditorFieldModel fieldModel : getFields()) { @@ -164,6 +173,12 @@ private String retrieveDisplayName(PatternFacade patternFacade) { public StringProperty titleProperty() { return title; } public void setTitle(String title) { this.title.set(title); } + // -- title visible + private BooleanProperty titleVisible = new SimpleBooleanProperty(false); + public boolean isTitleVisible() { return titleVisible.get(); } + public BooleanProperty titleVisibleProperty() { return titleVisible; } + public void setTitleVisible(boolean titleVisible) { this.titleVisible.set(titleVisible); } + // -- fields /** * The collection of EditorFieldModel (fields) this Pattern has. diff --git a/kview/src/main/java/dev/ikm/komet/kview/controls/ToggleSwitch.java b/kview/src/main/java/dev/ikm/komet/kview/controls/ToggleSwitch.java new file mode 100644 index 000000000..e53c0ea29 --- /dev/null +++ b/kview/src/main/java/dev/ikm/komet/kview/controls/ToggleSwitch.java @@ -0,0 +1,170 @@ +/** + * Copyright (c) 2015, Pixel Duke + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Pixel Duke, any associated website, nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.ikm.komet.kview.controls; + +import dev.ikm.komet.kview.controls.skin.FXToggleSwitchSkin; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.BooleanPropertyBase; +import javafx.css.PseudoClass; +import javafx.event.ActionEvent; +import javafx.scene.control.Labeled; +import javafx.scene.control.Skin; + +/** + * Much like a Toggle Button this control allows the user to toggle between one of two states. It has been popularized + * in touch based devices where its usage is particularly useful because unlike a checkbox the finger touch of a user + * doesn't obscure the control. + * + *

Shown below is a screenshot of the ToggleSwitch control in its on and off state: + *
+ *

+ * Screenshot of ToggleSwitch + *
+ */ +public class ToggleSwitch extends Labeled { + + /*************************************************************************** + * * + * Constructors * + * * + **************************************************************************/ + + /** + * Creates a toggle switch with empty string for its label. + */ + public ToggleSwitch() { + initialize(); + } + + /** + * Creates a toggle switch with the specified label. + * + * @param text The label string of the control. + */ + public ToggleSwitch(String text) { + super(text); + initialize(); + } + + private void initialize() { + getStyleClass().setAll(DEFAULT_STYLE_CLASS); + getStylesheets().add(getUserAgentStylesheet()); + } + + /*************************************************************************** + * * + * Properties * + * * + **************************************************************************/ + + /** + * Indicates whether this ToggleSwitch is selected. + */ + private BooleanProperty selected; + + /** + * Sets the selected value of this Toggle Switch + */ + public final void setSelected(boolean value) { + selectedProperty().set(value); + } + + /** + * Returns whether this Toggle Switch is selected + */ + public final boolean isSelected() { + return selected == null ? false : selected.get(); + } + + /** + * Returns the selected property + */ + public final BooleanProperty selectedProperty() { + if (selected == null) { + selected = new BooleanPropertyBase() { + @Override protected void invalidated() { + final Boolean v = get(); + pseudoClassStateChanged(PSEUDO_CLASS_SELECTED, v); +// accSendNotification(Attribute.SELECTED); + } + + @Override + public Object getBean() { + return ToggleSwitch.this; + } + + @Override + public String getName() { + return "selected"; + } + }; + } + return selected; + } + + + /*************************************************************************** + * * + * Methods * + * * + **************************************************************************/ + + /** + * Toggles the state of the {@code ToggleSwitch}. The {@code ToggleSwitch} will cycle through + * the selected and unselected states. + */ + public void fire() { + if (!isDisabled()) { + setSelected(!isSelected()); + fireEvent(new ActionEvent()); + } + } + + /** {@inheritDoc} */ + @Override protected Skin createDefaultSkin() { + return new FXToggleSwitchSkin(this); + } + + + /*************************************************************************** + * * + * Stylesheet Handling * + * * + **************************************************************************/ + + private static final String DEFAULT_STYLE_CLASS = "toggle-switch"; + + private static final PseudoClass PSEUDO_CLASS_SELECTED = + PseudoClass.getPseudoClass("selected"); + + /** {@inheritDoc} */ + @Override + public String getUserAgentStylesheet() { + return ToggleSwitch.class.getResource("toggleswitch.css").toExternalForm(); + } +} \ No newline at end of file diff --git a/kview/src/main/java/dev/ikm/komet/kview/controls/skin/FXToggleSwitchSkin.java b/kview/src/main/java/dev/ikm/komet/kview/controls/skin/FXToggleSwitchSkin.java new file mode 100644 index 000000000..61239c742 --- /dev/null +++ b/kview/src/main/java/dev/ikm/komet/kview/controls/skin/FXToggleSwitchSkin.java @@ -0,0 +1,320 @@ +/* + * FXSkins, + * Copyright (C) 2021 PixelDuke (Pedro Duque Vieira - www.pixelduke.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package dev.ikm.komet.kview.controls.skin; + +import dev.ikm.komet.kview.controls.ToggleSwitch; +import javafx.animation.Interpolator; +import javafx.animation.TranslateTransition; +import javafx.beans.InvalidationListener; +import javafx.beans.property.DoubleProperty; +import javafx.css.CssMetaData; +import javafx.css.SimpleStyleableObjectProperty; +import javafx.css.Styleable; +import javafx.css.StyleableDoubleProperty; +import javafx.css.StyleableObjectProperty; +import javafx.css.StyleableProperty; +import javafx.css.converter.EnumConverter; +import javafx.css.converter.SizeConverter; +import javafx.event.EventHandler; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.SkinBase; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.util.Duration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FXToggleSwitchSkin extends SkinBase { + private HBox mainContainer = new HBox(); + + private final Label label = new Label(); + private final StackPane labelContainer = new StackPane(); + private final InnerToggleSwitch innerToggleSwitch; + + private InvalidationListener thumbDisplayChanged = observable -> this.updateThumbDisplay(getThumbDisplay()); + + /** + * How many milliseconds it should take for the thumb to go from + * one edge to the other + */ + private DoubleProperty thumbMoveAnimationTime = null; + + private StyleableObjectProperty thumbDisplay = new SimpleStyleableObjectProperty<>(THUMB_DISPLAY_META_DATA, ThumbDisplay.LEFT) { + @Override + protected void invalidated() { + FXToggleSwitchSkin.this.getSkinnable().requestLayout(); + } + }; + + /** + * Constructor for all ToggleSwitchSkin instances. + * + * @param control The ToggleSwitch for which this Skin should attach to. + */ + public FXToggleSwitchSkin(ToggleSwitch control) { + super(control); + + innerToggleSwitch = new InnerToggleSwitch(this); + + label.textProperty().bind(control.textProperty()); + + mainContainer.getStyleClass().setAll("main-container"); + + getChildren().setAll(mainContainer); + + labelContainer.getChildren().addAll(label); + StackPane.setAlignment(label, Pos.CENTER_LEFT); + labelContainer.getStyleClass().setAll("label-container"); + + updateThumbDisplay(getThumbDisplay()); + thumbDisplay.addListener(thumbDisplayChanged); + } + + private void updateThumbDisplay(ThumbDisplay thumbDisplay) { + switch (thumbDisplay) { + case LEFT: + mainContainer.getChildren().setAll(innerToggleSwitch, labelContainer); + break; + case RIGHT: + mainContainer.getChildren().setAll(labelContainer, innerToggleSwitch); + break; + case THUMB_ONLY: + mainContainer.getChildren().setAll(innerToggleSwitch); + break; + } + + } + + @Override + public void dispose() { + thumbDisplay.removeListener(thumbDisplayChanged); + + super.dispose(); + } + + /*************************************************************************** + * * + * Properties * + * * + **************************************************************************/ + + // --- thumb move animation time + + private DoubleProperty thumbMoveAnimationTimeProperty() { + if (thumbMoveAnimationTime == null) { + thumbMoveAnimationTime = new StyleableDoubleProperty(200) { + + @Override + public Object getBean() { + return FXToggleSwitchSkin.this; + } + + @Override + public String getName() { + return "thumbMoveAnimationTime"; + } + + @Override + public CssMetaData getCssMetaData() { + return THUMB_MOVE_ANIMATION_TIME_META_DATA; + } + }; + } + return thumbMoveAnimationTime; + } + + private double getThumbMoveAnimationTime() { + return thumbMoveAnimationTime == null ? 200 : thumbMoveAnimationTime.get(); + } + + // --- thumb display + + private StyleableObjectProperty thumbDisplayProperty() { return thumbDisplay; } + + private ThumbDisplay getThumbDisplay() { return thumbDisplay.get(); } + + + /*************************************************************************** + * * + * CSS Handling * + * * + **************************************************************************/ + + private static final CssMetaData THUMB_MOVE_ANIMATION_TIME_META_DATA = + new CssMetaData<>("-thumb-move-animation-time", + SizeConverter.getInstance(), 200) { + + @Override + public boolean isSettable(ToggleSwitch toggleSwitch) { + final FXToggleSwitchSkin skin = (FXToggleSwitchSkin) toggleSwitch.getSkin(); + return skin.thumbMoveAnimationTime == null || + !skin.thumbMoveAnimationTime.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ToggleSwitch toggleSwitch) { + final FXToggleSwitchSkin skin = (FXToggleSwitchSkin) toggleSwitch.getSkin(); + return (StyleableProperty) skin.thumbMoveAnimationTimeProperty(); + } + }; + + private static final CssMetaData THUMB_DISPLAY_META_DATA = + new CssMetaData<>("-toggle-display", new EnumConverter<>(ThumbDisplay.class)) { + + @Override + public boolean isSettable(ToggleSwitch toggleSwitch) { + final FXToggleSwitchSkin skin = (FXToggleSwitchSkin) toggleSwitch.getSkin(); + return !skin.thumbDisplay.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ToggleSwitch toggleSwitch) { + final FXToggleSwitchSkin skin = (FXToggleSwitchSkin) toggleSwitch.getSkin(); + return skin.thumbDisplayProperty(); + } + }; + + private static final List> STYLEABLES; + + static { + final List> styleables = + new ArrayList<>(SkinBase.getClassCssMetaData()); + styleables.add(THUMB_MOVE_ANIMATION_TIME_META_DATA); + styleables.add(THUMB_DISPLAY_META_DATA); + STYLEABLES = Collections.unmodifiableList(styleables); + } + + /** + * @return The CssMetaData associated with this class, which may include the + * CssMetaData of its super classes. + */ + public static List> getClassCssMetaData() { + return STYLEABLES; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getCssMetaData() { + return getClassCssMetaData(); + } + + /**************************************************************************** + * * + * Supporting Classes / Enums * + * * + ***************************************************************************/ + + private enum ThumbDisplay { + LEFT, RIGHT, THUMB_ONLY + } + + private static class InnerToggleSwitch extends Region { + private boolean isFirstLayoutPass = true; + private final FXToggleSwitchSkin toggleSwitchSkin; + private final TranslateTransition transition; + + private final StackPane thumb = new StackPane(); + + private InvalidationListener selectionChanged = observable -> this.selectedStateChanged(); + private EventHandler mouseReleased; + + public InnerToggleSwitch(FXToggleSwitchSkin toggleSwitchSkin) { + transition = new TranslateTransition(Duration.millis(toggleSwitchSkin.getThumbMoveAnimationTime()), thumb); + transition.setInterpolator(Interpolator.EASE_OUT); + + this.toggleSwitchSkin = toggleSwitchSkin; + + getStyleClass().setAll("thumb-area"); + thumb.getStyleClass().setAll("thumb"); + + getChildren().add(thumb); + + thumb.setMouseTransparent(true); + + ToggleSwitch skinnable = toggleSwitchSkin.getSkinnable(); + + mouseReleased = event -> onMouseReleased(skinnable); + setOnMouseReleased(mouseReleased); + + initThumbTransformX(); + skinnable.selectedProperty().addListener(selectionChanged); + } + + private void onMouseReleased(ToggleSwitch toggleSwitch) { + toggleSwitch.setSelected(!toggleSwitch.isSelected()); + } + + private void initThumbTransformX() { + if (!toggleSwitchSkin.getSkinnable().isSelected()) { + thumb.setTranslateX(0); + } else { + thumb.setTranslateX(calculateSelectedToggleTranslateX()); + } + } + + private void selectedStateChanged() { + ToggleSwitch toggleSwitch = toggleSwitchSkin.getSkinnable(); + transition.stop(); + transition.setDuration(Duration.millis(toggleSwitchSkin.getThumbMoveAnimationTime())); + + double thumbTranslateSelectedX = calculateSelectedToggleTranslateX(); + + if (!toggleSwitch.isSelected()) { // selected to not selected + transition.setFromX(thumbTranslateSelectedX); + transition.setToX(0); + } else { // not selected to selected + transition.setFromX(0); + transition.setToX(thumbTranslateSelectedX); + } + transition.setCycleCount(1); + transition.play(); + } + + private double calculateSelectedToggleTranslateX() { + double thumbAreaWidth = getWidth() - (snappedLeftInset() + snappedRightInset()); + double thumbWidth = snapSizeX(thumb.prefWidth(-1)); + return thumbAreaWidth - thumbWidth; + } + + @Override + protected void layoutChildren() { + final double x = snappedLeftInset(); + final double y = snappedTopInset(); + final double height = getHeight() - (snappedTopInset() + snappedBottomInset()); + + double thumbWidth = thumb.prefWidth(-1); + double thumbHeight = thumb.prefHeight(-1); + thumb.resize(snapSizeX(thumbWidth), snapSizeY(thumbHeight)); + + thumb.setLayoutX(snapPositionX(x)); + thumb.setLayoutY(snapPositionY(y + height / 2d) - thumbHeight / 2); + + if (isFirstLayoutPass) { + initThumbTransformX(); + } + } + } +} \ No newline at end of file diff --git a/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java b/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java index 2fea0de50..69f450226 100644 --- a/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java +++ b/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java @@ -556,6 +556,8 @@ private void addPatternView(EditorPatternModel editorPatternModel, PatternEntity // Pattern title Label patternTitle = new Label(editorPatternModel.getTitle()); patternTitle.getStyleClass().add("gen-purpose-pattern-title"); + patternTitle.visibleProperty().bind(editorPatternModel.titleVisibleProperty()); + patternTitle.managedProperty().bind(editorPatternModel.titleVisibleProperty()); patternMainContainer.getChildren().add(patternTitle); ConceptFacade author = getViewProperties().nodeView().editCoordinate().getAuthorForChanges(); diff --git a/kview/src/main/resources/dev/ikm/komet/kview/controls/toggleswitch.css b/kview/src/main/resources/dev/ikm/komet/kview/controls/toggleswitch.css new file mode 100644 index 000000000..8dd4508f2 --- /dev/null +++ b/kview/src/main/resources/dev/ikm/komet/kview/controls/toggleswitch.css @@ -0,0 +1,53 @@ +.toggle-switch { + -thumb-move-animation-time: 100; + -toggle-display: right; + + -fx-pref-height: 1.666666em; /* 20 */ + -fx-max-height: 1.666666em; /* 20 */ + -fx-min-height: 1.666666em; /* 20 */ + + -fx-font-family: "Noto Sans"; + -fx-font-size: 1em; +} + +.toggle-switch > .main-container { + -fx-spacing: 10; +} + +.toggle-switch .thumb { + -fx-background-color: #bbb, white; + -fx-background-insets: 0, 1; + -fx-background-radius: 1.0em; /* large value to make sure this remains circular */ + -fx-padding: 7.6px; + -fx-alignment: CENTER; + -fx-content-display: LEFT; +} + +.toggle-switch > .main-container > .thumb-area { + -fx-background-radius: 1em; + -fx-background-color: #4a7ad2; + -fx-background-insets: 0; + + -fx-pref-width: 34px; + -fx-max-width: 34px; + -fx-min-width: 34px; + + -fx-padding: 3.6px 2px 4px 2px; +} + +.toggle-switch:hover .thumb { + -fx-background-color: #eee; +} + +.toggle-switch:selected:hover .thumb { + -fx-background-color: #eee; +} + +.toggle-switch:selected > .main-container > .thumb-area { + -fx-background-color: #5dcf16; + -fx-background-insets: 0; +} + +.toggle-switch:disabled { + -fx-opacity: 0.4; +} \ No newline at end of file diff --git a/preferences/src/main/java/dev/ikm/komet/preferences/KLEditorPreferences.java b/preferences/src/main/java/dev/ikm/komet/preferences/KLEditorPreferences.java index 145319b55..c82a4341a 100644 --- a/preferences/src/main/java/dev/ikm/komet/preferences/KLEditorPreferences.java +++ b/preferences/src/main/java/dev/ikm/komet/preferences/KLEditorPreferences.java @@ -53,4 +53,8 @@ public class GridLayoutKey { */ public static String KL_GRID_COLUMN_SPAN = "kl-grid-node-column-span"; } + + public class PatternKey { + public static String PATTERN_TITLE_VISIBLE = "pattern-title-visible"; + } } \ No newline at end of file From cc872bd88eaed72700e5feddd426e38ba75d45a2 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Thu, 15 Jan 2026 14:15:10 +0000 Subject: [PATCH 06/15] Tweak KL Editor TextField visuals when the TextField is readonly --- .../main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css index a1186b09b..3a7683499 100644 --- a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css +++ b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css @@ -187,6 +187,10 @@ -fx-border-width: 0; } +.text-field:readonly { + -fx-opacity: 0.4; +} + .text-field:focused { -fx-background-color: #8ab4f8, white; -fx-background-insets: 0, 2; From f903aa5fcb13c8787065e2afc46153c49592922d Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Fri, 16 Jan 2026 00:08:20 +0000 Subject: [PATCH 07/15] FVKB-151: Show available factories in the Display section in the Properties Pane when a Field is selected --- .../view/KLEditorWindowController.java | 2 + .../view/control/FieldViewControl.java | 6 ++ .../propertiespane/FieldPropertiesPane.java | 64 ++++++++++++++++++- .../src/main/java/module-info.java | 8 +++ .../layout/editor/model/EditorFieldModel.java | 6 ++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java index a904d56b3..69dea2b82 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java @@ -143,6 +143,8 @@ private void addFieldView(EditorPatternModel patternModel, EditorFieldModel fiel fieldViewControl.rowIndexProperty().bindBidirectional(fieldModel.rowIndexProperty()); fieldViewControl.columnSpanProperty().bindBidirectional(fieldModel.columnSpanProperty()); + fieldViewControl.dataTypeNidProperty().bind(fieldModel.dataTypeNidProperty()); + PatternViewControl patternViewControl = patternModelToView.get(patternModel); patternViewControl.getFields().add(fieldViewControl); } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java index c3f53cdfd..c99bb2d92 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java @@ -73,4 +73,10 @@ protected void layoutChildren() { public int getFieldNumber() { return fieldNumber.get(); } public IntegerProperty fieldNumberProperty() { return fieldNumber; } public void setFieldNumber(int number) { fieldNumber.set(number); } + + // -- data type nid + private final IntegerProperty dataTypeNid = new SimpleIntegerProperty(); + public int getDataTypeNid() { return dataTypeNid.get(); } + public IntegerProperty dataTypeNidProperty() { return dataTypeNid; } + public void setDataTypeNid(int value) { dataTypeNid.set(value); } } \ No newline at end of file diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java index ba524e68d..07bc85027 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java @@ -1,6 +1,15 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; import dev.ikm.komet.kleditorapp.view.control.FieldViewControl; +import dev.ikm.komet.layout.KlRestorable; +import dev.ikm.komet.layout.area.KlAreaForBoolean; +import dev.ikm.komet.layout.area.KlAreaForComponent; +import dev.ikm.komet.layout.area.KlAreaForFloat; +import dev.ikm.komet.layout.area.KlAreaForImage; +import dev.ikm.komet.layout.area.KlAreaForIntIdList; +import dev.ikm.komet.layout.area.KlAreaForIntIdSet; +import dev.ikm.komet.layout.area.KlAreaForInteger; +import dev.ikm.komet.layout.area.KlAreaForString; import javafx.geometry.HPos; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; @@ -11,11 +20,25 @@ import javafx.scene.layout.RowConstraints; import javafx.scene.layout.VBox; +import java.util.ServiceLoader; + +import static dev.ikm.tinkar.terms.TinkarTerm.BOOLEAN_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.COMPONENT_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.COMPONENT_ID_LIST_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.COMPONENT_ID_SET_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.CONCEPT_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.FLOAT; +import static dev.ikm.tinkar.terms.TinkarTerm.FLOAT_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.IMAGE_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.INTEGER_FIELD; +import static dev.ikm.tinkar.terms.TinkarTerm.STRING; +import static dev.ikm.tinkar.terms.TinkarTerm.STRING_FIELD; + public class FieldPropertiesPane extends GridNodePropertiesPane { public static final String DEFAULT_STYLE_CLASS = "field-properties"; private final VBox fieldMainContainer = new VBox(); - private final ComboBox displayComboBox; + private final ComboBox displayComboBox; public FieldPropertiesPane() { VBox titleContainer = new VBox(); @@ -84,4 +107,43 @@ public FieldPropertiesPane() { getStyleClass().add(DEFAULT_STYLE_CLASS); fieldMainContainer.getStyleClass().add("field-main-container"); } + + @Override + protected void doInit(FieldViewControl control) { + super.doInit(control); + + // Display + displayComboBox.getItems().clear(); + int dataTypeNid = control.getDataTypeNid(); + ServiceLoader loader = null; + if (dataTypeNid == COMPONENT_FIELD.nid()) { + loader = ServiceLoader.load(KlAreaForComponent.Factory.class); + } else if (dataTypeNid == CONCEPT_FIELD.nid()) { + loader = ServiceLoader.load(KlAreaForComponent.Factory.class); + } else if (dataTypeNid == STRING_FIELD.nid() || dataTypeNid == STRING.nid()) { + loader = ServiceLoader.load(KlAreaForString.Factory.class); + } else if (dataTypeNid == COMPONENT_ID_SET_FIELD.nid()) { + ServiceLoader.load(KlAreaForIntIdSet.Factory.class); + } else if (dataTypeNid == COMPONENT_ID_LIST_FIELD.nid()) { + ServiceLoader.load(KlAreaForIntIdList.Factory.class); + } else if (dataTypeNid == FLOAT_FIELD.nid() || dataTypeNid == FLOAT.nid()) { + loader = ServiceLoader.load(KlAreaForFloat.Factory.class); + } else if (dataTypeNid == INTEGER_FIELD.nid()) { + loader = ServiceLoader.load(KlAreaForInteger.Factory.class); + } else if (dataTypeNid == BOOLEAN_FIELD.nid()) { + loader = ServiceLoader.load(KlAreaForBoolean.Factory.class); + } else if (dataTypeNid == IMAGE_FIELD.nid()) { + loader = ServiceLoader.load(KlAreaForImage.Factory.class); +// } else if (dataTypeNid == BYTE_ARRAY_FIELD.nid()) { +// loader = ServiceLoader.load(KlAreaForB.Factory.class); + } else { + loader = ServiceLoader.load(KlAreaForString.Factory.class); + } + + if (loader != null) { + for (KlRestorable.Factory factory : loader) { + displayComboBox.getItems().add(factory.factoryName()); + } + } + } } diff --git a/knowledge-layout-editor/src/main/java/module-info.java b/knowledge-layout-editor/src/main/java/module-info.java index 795441b89..65366fbea 100644 --- a/knowledge-layout-editor/src/main/java/module-info.java +++ b/knowledge-layout-editor/src/main/java/module-info.java @@ -48,4 +48,12 @@ exports dev.ikm.komet.kleditorapp.view.propertiespane; uses EntityKlWindowFactory; + uses dev.ikm.komet.layout.area.KlAreaForString.Factory; + uses dev.ikm.komet.layout.area.KlAreaForComponent.Factory; + uses dev.ikm.komet.layout.area.KlAreaForIntIdSet.Factory; + uses dev.ikm.komet.layout.area.KlAreaForIntIdList.Factory; + uses dev.ikm.komet.layout.area.KlAreaForFloat.Factory; + uses dev.ikm.komet.layout.area.KlAreaForInteger.Factory; + uses dev.ikm.komet.layout.area.KlAreaForBoolean.Factory; + uses dev.ikm.komet.layout.area.KlAreaForImage.Factory; } diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java index 82ffdeadc..6ee40a6ff 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java @@ -32,6 +32,7 @@ public EditorFieldModel(ViewCalculator viewCalculator, FieldDefinitionRecord fie title.set(fieldDefinitionRecord.meaning().description()); index.set(fieldDefinitionRecord.indexInPattern()); + dataTypeNid.set(fieldDefinitionRecord.dataTypeNid()); } /** @@ -76,4 +77,9 @@ public void save(KometPreferences patternPreferences) { private ReadOnlyIntegerWrapper index = new ReadOnlyIntegerWrapper(); public int getIndex() { return index.get(); } public ReadOnlyIntegerProperty indexProperty() { return index.getReadOnlyProperty(); } + + // -- data type nid + private ReadOnlyIntegerWrapper dataTypeNid = new ReadOnlyIntegerWrapper(); + public int getDataTypeNid() { return dataTypeNid.get(); } + public ReadOnlyIntegerProperty dataTypeNidProperty() { return dataTypeNid.getReadOnlyProperty(); } } From 09ebf340e8700da4b9cb2eb1d8c78eab05411ebe Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Fri, 16 Jan 2026 12:47:03 +0000 Subject: [PATCH 08/15] FVKB-153: Pressing delete to delete a Pattern after it's added is not working --- .../view/ControlBasePropertiesPane.java | 16 +++++++------- .../propertiespane/FieldPropertiesPane.java | 2 ++ .../GridNodePropertiesPane.java | 5 +++-- .../propertiespane/PatternPropertiesPane.java | 2 ++ .../propertiespane/SectionPropertiesPane.java | 2 ++ .../view/skin/EditorGridPaneSkin.java | 21 ++++++++++++++++--- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java index 52c07580b..81c151d84 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java @@ -21,14 +21,16 @@ public abstract class ControlBasePropertiesPane displayComboBox; public FieldPropertiesPane() { + super(false); + VBox titleContainer = new VBox(); titleContainer.getStyleClass().add("title-container"); titleContainer.setSpacing(4); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java index 9b896d6db..bee2ce671 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java @@ -30,7 +30,9 @@ public class GridNodePropertiesPane extends ControlBa protected final Label positioningLabel; protected final GridPane positioningGridPane; - public GridNodePropertiesPane() { + public GridNodePropertiesPane(boolean isDeletable) { + super(isDeletable); + // "POSITIONING" label positioningLabel = new Label("POSITIONING"); positioningLabel.getStyleClass().add("group-title"); @@ -97,7 +99,6 @@ public GridNodePropertiesPane() { rowSpanCB.setItems((FXCollections.observableArrayList(List.of(1, 2, 3)))); rowSpanCB.setMaxWidth(Double.MAX_VALUE); positioningGridPane.add(rowSpanCB, 1, 3); - } @Override diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java index ea8493931..36c410016 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java @@ -30,6 +30,8 @@ public class PatternPropertiesPane extends GridNodePropertiesPane previousControlColumnsObjProperty; public PatternPropertiesPane() { + super(true); + // Section name container VBox titleContainer = new VBox(); titleContainer.getStyleClass().add("title-container"); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java index 07e1174b5..cec0f9a4d 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java @@ -28,6 +28,8 @@ public class SectionPropertiesPane extends ControlBasePropertiesPane lastColumnsSectionProperty; public SectionPropertiesPane() { + super(true); + // Section name container VBox sectionNameContainer = new VBox(); sectionNameContainer.getStyleClass().add("section-name-container"); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java index 1e5ba84eb..93ec68257 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java @@ -26,18 +26,20 @@ import javafx.scene.shape.Rectangle; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Optional; public class EditorGridPaneSkin extends SkinBase { private static final int DRAG_LINE_THICKNESS = 5; - private static final PseudoClass MOUSE_HOVER_WHILE_DRAGGING_PSEUDO_CLASS = PseudoClass.getPseudoClass("mouse-hover-dragging"); private final GridPane gridPane = new GridPane(); private final List gridTiles = new ArrayList<>(); private GridTile currentMouseHoverGridTile; + private HashMap> gridControlDragHandles = new HashMap<>(); + /** * Constructor for EditorGridPaneSkin instances. * @@ -82,6 +84,13 @@ private void onItemsChanged(ListChangeListener.Change initGridControl(gridBaseControl); }); } + if (change.wasRemoved()) { + change.getRemoved().forEach(gridControl -> { + gridPane.getChildren().removeAll(gridControl); + gridPane.getChildren().removeAll(gridControlDragHandles.get(gridControl)); + gridControlDragHandles.remove(gridControl); + }); + } } updateTiles(); } @@ -202,13 +211,17 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) bottomEdge.setFill(Color.TRANSPARENT); bottomEdge.setStroke(Color.TRANSPARENT); - // Add children to scene graph - getChildren().addAll( + List dragHandles = List.of( rectWhileDragging, rightEdge, bottomEdge ); + // Add children to scene graph AND + // add dragHandles to map with gridBaseControl key + getChildren().addAll(dragHandles); + gridControlDragHandles.put(gridBaseControl, dragHandles); + gridBaseControl.boundsInParentProperty().subscribe(bounds -> { // Update drag handles and drag visuals if control changes bounds Bounds gridControlBounds = gridPane.localToParent(bounds); @@ -275,6 +288,8 @@ private void addDragHandles(GridPane gridPane, GridBaseControl gridBaseControl) currentMouseHoverGridTile = null; }); + //===================== Setup mouse events on Bottom Edge ========================== + bottomEdge.setOnMouseDragged(mouseEvent -> { double mouseY = bottomEdge.localToParent(0, mouseEvent.getY()).getY(); From ab25d6d0a35f11f559c638843079180c406d6793 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Mon, 19 Jan 2026 17:05:52 +0000 Subject: [PATCH 09/15] Refactor creating WindowControlFactory to improve code for Window controls creation --- .../view/KLEditorWindowController.java | 54 +++----------- .../view/control/WindowControlFactory.java | 72 +++++++++++++++++++ .../propertiespane/FieldPropertiesPane.java | 15 ++-- .../editor/model/EditorGridNodeModel.java | 2 +- .../layout/editor/model/EditorModelBase.java | 4 ++ .../editor/model/EditorSectionModel.java | 2 +- 6 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java create mode 100644 knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java index 69dea2b82..a025200e9 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java @@ -4,6 +4,7 @@ import dev.ikm.komet.kleditorapp.view.control.FieldViewControl; import dev.ikm.komet.kleditorapp.view.control.PatternViewControl; import dev.ikm.komet.kleditorapp.view.control.SectionViewControl; +import dev.ikm.komet.kleditorapp.view.control.WindowControlFactory; import dev.ikm.komet.layout.editor.EditorWindowManager; import dev.ikm.komet.layout.editor.model.EditorFieldModel; import dev.ikm.komet.layout.editor.model.EditorPatternModel; @@ -18,23 +19,17 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; -import java.util.HashMap; import java.util.List; import static dev.ikm.komet.kleditorapp.view.control.PatternBrowserCell.KL_EDITOR_VERSION_PROXY; public class KLEditorWindowController { - private EditorWindowControl editorWindowControl; + private final EditorWindowControl editorWindowControl; - private ViewCalculator viewCalculator; + private final ViewCalculator viewCalculator; - private final HashMap sectionViewToModel = new HashMap<>(); - private final HashMap sectionModelToView = new HashMap<>(); - - private final HashMap patternModelToView = new HashMap<>(); - - private EditorWindowModel editorWindowModel; + private final EditorWindowModel editorWindowModel; public KLEditorWindowController(EditorWindowModel editorWindowModel, EditorWindowControl editorWindowControl, ViewCalculator viewCalculator) { this.viewCalculator = viewCalculator; @@ -77,15 +72,7 @@ private void addSectionViewAndPatterns(List sectio } private void addSectionView(EditorSectionModel editorSectionModel) { - SectionViewControl sectionViewControl = new SectionViewControl(); - - sectionViewControl.nameProperty().bindBidirectional(editorSectionModel.nameProperty()); - sectionViewControl.tagTextProperty().bind(editorSectionModel.tagTextProperty()); - - sectionViewControl.numberColumnsProperty().bindBidirectional(editorSectionModel.numberColumnsProperty()); - - sectionViewToModel.put(sectionViewControl, editorSectionModel); - sectionModelToView.put(editorSectionModel, sectionViewControl); + SectionViewControl sectionViewControl = WindowControlFactory.createSectionView(editorSectionModel); setupDragAndDrop(sectionViewControl); @@ -100,23 +87,12 @@ private void addPatternViews(EditorSectionModel editorSectionModel, List) change -> onPatternModelFieldsChanged(patternModel, change)); - SectionViewControl sectionViewControl = sectionModelToView.get(editorSectionModel); + SectionViewControl sectionViewControl = (SectionViewControl) WindowControlFactory.getView(editorSectionModel); sectionViewControl.getPatterns().add(patternViewControl); } @@ -135,22 +111,14 @@ private void addFieldViews(EditorPatternModel patternModel, List { if (dragEvent.getDragboard().hasContent(KL_EDITOR_VERSION_PROXY)) { @@ -196,7 +164,7 @@ private void onAddSectionAction(ActionEvent actionEvent) { */ public void start() { // Select main section initially - SelectionManager.instance().setSelectedControl(sectionModelToView.get(editorWindowModel.getMainSection())); + SelectionManager.instance().setSelectedControl(WindowControlFactory.getView(editorWindowModel.getMainSection())); } public void shutdown() { diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java new file mode 100644 index 000000000..1b24cfcf3 --- /dev/null +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java @@ -0,0 +1,72 @@ +package dev.ikm.komet.kleditorapp.view.control; + +import dev.ikm.komet.layout.editor.model.EditorFieldModel; +import dev.ikm.komet.layout.editor.model.EditorModelBase; +import dev.ikm.komet.layout.editor.model.EditorPatternModel; +import dev.ikm.komet.layout.editor.model.EditorSectionModel; + +import java.util.HashMap; + +public class WindowControlFactory { + private static final HashMap windowControlToModel = new HashMap<>(); + private static final HashMap modelToWindowControl = new HashMap<>(); + + public static SectionViewControl createSectionView(EditorSectionModel editorSectionModel) { + SectionViewControl sectionViewControl = new SectionViewControl(); + + sectionViewControl.nameProperty().bindBidirectional(editorSectionModel.nameProperty()); + sectionViewControl.tagTextProperty().bind(editorSectionModel.tagTextProperty()); + + sectionViewControl.numberColumnsProperty().bindBidirectional(editorSectionModel.numberColumnsProperty()); + + updateMaps(editorSectionModel, sectionViewControl); + + return sectionViewControl; + } + + public static PatternViewControl createPatternView(EditorPatternModel editorPatternModel) { + PatternViewControl patternViewControl = new PatternViewControl(); + + patternViewControl.titleProperty().bind(editorPatternModel.titleProperty()); + patternViewControl.titleVisibleProperty().bindBidirectional(editorPatternModel.titleVisibleProperty()); + + patternViewControl.numberColumnsProperty().bindBidirectional(editorPatternModel.numberColumnsProperty()); + + patternViewControl.columnIndexProperty().bindBidirectional(editorPatternModel.columnIndexProperty()); + patternViewControl.rowIndexProperty().bindBidirectional(editorPatternModel.rowIndexProperty()); + patternViewControl.columnSpanProperty().bindBidirectional(editorPatternModel.columnSpanProperty()); + + updateMaps(editorPatternModel, patternViewControl); + + return patternViewControl; + } + + public static FieldViewControl createFieldView(EditorFieldModel editorFieldModel) { + FieldViewControl fieldViewControl = new FieldViewControl(); + fieldViewControl.titleProperty().bind(editorFieldModel.titleProperty()); + fieldViewControl.fieldNumberProperty().bind(editorFieldModel.indexProperty().add(1)); + + fieldViewControl.columnIndexProperty().bindBidirectional(editorFieldModel.columnIndexProperty()); + fieldViewControl.rowIndexProperty().bindBidirectional(editorFieldModel.rowIndexProperty()); + fieldViewControl.columnSpanProperty().bindBidirectional(editorFieldModel.columnSpanProperty()); + + fieldViewControl.dataTypeNidProperty().bind(editorFieldModel.dataTypeNidProperty()); + + updateMaps(editorFieldModel, fieldViewControl); + + return fieldViewControl; + } + + public static EditorModelBase getModel(EditorWindowBaseControl editorWindowBaseControl) { + return windowControlToModel.get(editorWindowBaseControl); + } + + public static EditorWindowBaseControl getView(EditorModelBase editorModelBase) { + return modelToWindowControl.get(editorModelBase); + } + + private static void updateMaps(EditorModelBase editorModelBase, EditorWindowBaseControl editorWindowBaseControl) { + windowControlToModel.put(editorWindowBaseControl, editorModelBase); + modelToWindowControl.put(editorModelBase, editorWindowBaseControl); + } +} diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java index f411c46e2..d88a27f6f 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java @@ -110,13 +110,11 @@ public FieldPropertiesPane() { fieldMainContainer.getStyleClass().add("field-main-container"); } - @Override - protected void doInit(FieldViewControl control) { - super.doInit(control); - - // Display + private void populateDisplayComboBox(FieldViewControl control) { displayComboBox.getItems().clear(); + int dataTypeNid = control.getDataTypeNid(); + ServiceLoader loader = null; if (dataTypeNid == COMPONENT_FIELD.nid()) { loader = ServiceLoader.load(KlAreaForComponent.Factory.class); @@ -148,4 +146,11 @@ protected void doInit(FieldViewControl control) { } } } + + @Override + protected void doInit(FieldViewControl control) { + super.doInit(control); + + populateDisplayComboBox(control); + } } diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java index a76712aa4..ec8f3b4fa 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java @@ -11,7 +11,7 @@ /** * Base class for any Editor model that stores in grid cell specific settings */ -public abstract class EditorGridNodeModel { +public abstract class EditorGridNodeModel extends EditorModelBase { protected void saveGridNodeDetails(KometPreferences preferences) { preferences.putInt(KL_GRID_COLUMN_INDEX, getColumnIndex()); diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java new file mode 100644 index 000000000..111733008 --- /dev/null +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java @@ -0,0 +1,4 @@ +package dev.ikm.komet.layout.editor.model; + +public class EditorModelBase { +} \ No newline at end of file diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java index b675ab914..5e38eaed3 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java @@ -22,7 +22,7 @@ * Represents a Section. It has properties like the Section name, the patterns inside it (EditorPatternModel instances), * number of columns, tag text (e.g. "Section 1"). */ -public class EditorSectionModel { +public class EditorSectionModel extends EditorModelBase { private static final Logger LOG = LoggerFactory.getLogger(EditorSectionModel.class); public static final String UNTITLED_SECTION_NAME = "Untitled"; From e5cd95631dccd9e945bee4a77477008b8df1db41 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Mon, 19 Jan 2026 23:08:04 +0000 Subject: [PATCH 10/15] Refactor: using Editor model instances instead of Views where appropriate --- .../view/ControlBasePropertiesPane.java | 12 +++---- .../view/KLEditorWindowController.java | 16 ++++++++-- .../view/control/FieldViewControl.java | 6 ---- .../view/control/WindowControlFactory.java | 18 ++++++----- .../propertiespane/FieldPropertiesPane.java | 14 ++++---- .../GridNodePropertiesPane.java | 14 ++++---- .../propertiespane/PatternPropertiesPane.java | 14 ++++---- .../view/propertiespane/PropertiesPane.java | 3 +- .../propertiespane/SectionPropertiesPane.java | 6 ++-- .../view/skin/EditorGridPaneSkin.java | 1 + .../layout/editor/model/EditorFieldModel.java | 13 ++++++++ .../editor/model/EditorGridNodeModel.java | 9 ++++++ .../layout/editor/model/EditorModelBase.java | 3 +- .../editor/model/EditorPatternModel.java | 24 +++++++++++++- .../editor/model/EditorSectionModel.java | 32 +++++++++++++++++++ .../editor/model/EditorWindowModel.java | 4 +++ 16 files changed, 140 insertions(+), 49 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java index 81c151d84..f6bd932d2 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/ControlBasePropertiesPane.java @@ -1,6 +1,6 @@ package dev.ikm.komet.kleditorapp.view; -import dev.ikm.komet.kleditorapp.view.control.EditorWindowBaseControl; +import dev.ikm.komet.layout.editor.model.EditorModelBase; import javafx.beans.property.Property; import javafx.event.ActionEvent; import javafx.scene.control.Button; @@ -12,13 +12,13 @@ import java.util.Objects; import java.util.function.Function; -public abstract class ControlBasePropertiesPane extends Region { +public abstract class ControlBasePropertiesPane extends Region { protected final BorderPane mainContainer = new BorderPane(); private final HBox bottomContainer = new HBox(); private final Button deleteButton = new Button(); - protected T currentlyShownControl; + protected T currentlyShownModel; protected T previouslyShownControl; public ControlBasePropertiesPane(boolean isDeletable) { @@ -60,7 +60,7 @@ public static Subscription bindBidirectionalWithConverter( } private void onDelete(ActionEvent event) { - currentlyShownControl.delete(); + currentlyShownModel.delete(); } /** @@ -69,8 +69,8 @@ private void onDelete(ActionEvent event) { * @param control the control to initialize the properties panel to. */ public final void initControl(T control){ - previouslyShownControl = currentlyShownControl; - currentlyShownControl = control; + previouslyShownControl = currentlyShownModel; + currentlyShownModel = control; doInit(control); } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java index a025200e9..dfe6796ca 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java @@ -53,14 +53,26 @@ private void onAdditionalSectionsChanged(ListChangeListener.Change { + editorWindowControl.getSectionViews().remove((SectionViewControl) WindowControlFactory.getView(sectionModel)); + }); + } } } - private void onSectionModelPatternsChanged(EditorSectionModel sectionModel, ListChangeListener.Change change) { + private void onSectionModelPatternsChanged(EditorSectionModel sectionModel, SectionViewControl sectionViewControl, + ListChangeListener.Change change) { while(change.next()) { if (change.wasAdded()) { addPatternViews(sectionModel, change.getAddedSubList()); } + if (change.wasRemoved()) { + change.getRemoved().forEach(patternModel -> { + PatternViewControl patternViewControl = (PatternViewControl) WindowControlFactory.getView(patternModel); + sectionViewControl.getPatterns().remove(patternViewControl); + }); + } } } @@ -150,7 +162,7 @@ private void setupDragAndDrop(SectionViewControl sectionViewControl) { }); // Listen to changes on Section Patterns - editorSectionModel.getPatterns().addListener((ListChangeListener) change -> onSectionModelPatternsChanged(editorSectionModel, change)); + editorSectionModel.getPatterns().addListener((ListChangeListener) change -> onSectionModelPatternsChanged(editorSectionModel, sectionViewControl, change)); } @FXML diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java index c99bb2d92..c3f53cdfd 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/FieldViewControl.java @@ -73,10 +73,4 @@ protected void layoutChildren() { public int getFieldNumber() { return fieldNumber.get(); } public IntegerProperty fieldNumberProperty() { return fieldNumber; } public void setFieldNumber(int number) { fieldNumber.set(number); } - - // -- data type nid - private final IntegerProperty dataTypeNid = new SimpleIntegerProperty(); - public int getDataTypeNid() { return dataTypeNid.get(); } - public IntegerProperty dataTypeNidProperty() { return dataTypeNid; } - public void setDataTypeNid(int value) { dataTypeNid.set(value); } } \ No newline at end of file diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java index 1b24cfcf3..9a516dd7c 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/WindowControlFactory.java @@ -1,6 +1,7 @@ package dev.ikm.komet.kleditorapp.view.control; import dev.ikm.komet.layout.editor.model.EditorFieldModel; +import dev.ikm.komet.layout.editor.model.EditorGridNodeModel; import dev.ikm.komet.layout.editor.model.EditorModelBase; import dev.ikm.komet.layout.editor.model.EditorPatternModel; import dev.ikm.komet.layout.editor.model.EditorSectionModel; @@ -32,9 +33,7 @@ public static PatternViewControl createPatternView(EditorPatternModel editorPatt patternViewControl.numberColumnsProperty().bindBidirectional(editorPatternModel.numberColumnsProperty()); - patternViewControl.columnIndexProperty().bindBidirectional(editorPatternModel.columnIndexProperty()); - patternViewControl.rowIndexProperty().bindBidirectional(editorPatternModel.rowIndexProperty()); - patternViewControl.columnSpanProperty().bindBidirectional(editorPatternModel.columnSpanProperty()); + bindGridNodeProperties(editorPatternModel, patternViewControl); updateMaps(editorPatternModel, patternViewControl); @@ -46,11 +45,7 @@ public static FieldViewControl createFieldView(EditorFieldModel editorFieldModel fieldViewControl.titleProperty().bind(editorFieldModel.titleProperty()); fieldViewControl.fieldNumberProperty().bind(editorFieldModel.indexProperty().add(1)); - fieldViewControl.columnIndexProperty().bindBidirectional(editorFieldModel.columnIndexProperty()); - fieldViewControl.rowIndexProperty().bindBidirectional(editorFieldModel.rowIndexProperty()); - fieldViewControl.columnSpanProperty().bindBidirectional(editorFieldModel.columnSpanProperty()); - - fieldViewControl.dataTypeNidProperty().bind(editorFieldModel.dataTypeNidProperty()); + bindGridNodeProperties(editorFieldModel, fieldViewControl); updateMaps(editorFieldModel, fieldViewControl); @@ -69,4 +64,11 @@ private static void updateMaps(EditorModelBase editorModelBase, EditorWindowBase windowControlToModel.put(editorWindowBaseControl, editorModelBase); modelToWindowControl.put(editorModelBase, editorWindowBaseControl); } + + private static void bindGridNodeProperties(EditorGridNodeModel gridNodeModel, GridBaseControl gridBaseControl) { + gridBaseControl.columnIndexProperty().bindBidirectional(gridNodeModel.columnIndexProperty()); + gridBaseControl.rowIndexProperty().bindBidirectional(gridNodeModel.rowIndexProperty()); + gridBaseControl.columnSpanProperty().bindBidirectional(gridNodeModel.columnSpanProperty()); + gridBaseControl.rowSpanProperty().bindBidirectional(gridNodeModel.rowSpanProperty()); + } } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java index d88a27f6f..be0a78751 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java @@ -1,6 +1,5 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; -import dev.ikm.komet.kleditorapp.view.control.FieldViewControl; import dev.ikm.komet.layout.KlRestorable; import dev.ikm.komet.layout.area.KlAreaForBoolean; import dev.ikm.komet.layout.area.KlAreaForComponent; @@ -10,6 +9,7 @@ import dev.ikm.komet.layout.area.KlAreaForIntIdSet; import dev.ikm.komet.layout.area.KlAreaForInteger; import dev.ikm.komet.layout.area.KlAreaForString; +import dev.ikm.komet.layout.editor.model.EditorFieldModel; import javafx.geometry.HPos; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; @@ -34,7 +34,7 @@ import static dev.ikm.tinkar.terms.TinkarTerm.STRING; import static dev.ikm.tinkar.terms.TinkarTerm.STRING_FIELD; -public class FieldPropertiesPane extends GridNodePropertiesPane { +public class FieldPropertiesPane extends GridNodePropertiesPane { public static final String DEFAULT_STYLE_CLASS = "field-properties"; private final VBox fieldMainContainer = new VBox(); @@ -110,10 +110,10 @@ public FieldPropertiesPane() { fieldMainContainer.getStyleClass().add("field-main-container"); } - private void populateDisplayComboBox(FieldViewControl control) { + private void populateDisplayComboBox(EditorFieldModel modelObject) { displayComboBox.getItems().clear(); - int dataTypeNid = control.getDataTypeNid(); + int dataTypeNid = modelObject.getDataTypeNid(); ServiceLoader loader = null; if (dataTypeNid == COMPONENT_FIELD.nid()) { @@ -148,9 +148,9 @@ private void populateDisplayComboBox(FieldViewControl control) { } @Override - protected void doInit(FieldViewControl control) { - super.doInit(control); + protected void doInit(EditorFieldModel modelObject) { + super.doInit(modelObject); - populateDisplayComboBox(control); + populateDisplayComboBox(modelObject); } } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java index bee2ce671..9c01e5e78 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/GridNodePropertiesPane.java @@ -1,7 +1,7 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; import dev.ikm.komet.kleditorapp.view.ControlBasePropertiesPane; -import dev.ikm.komet.kleditorapp.view.control.GridBaseControl; +import dev.ikm.komet.layout.editor.model.EditorGridNodeModel; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.geometry.HPos; @@ -15,7 +15,7 @@ import java.util.List; -public class GridNodePropertiesPane extends ControlBasePropertiesPane { +public class GridNodePropertiesPane extends ControlBasePropertiesPane { protected final ComboBox columnPositionCB = new ComboBox<>(); protected final ComboBox rowPositionCB = new ComboBox<>(); @@ -102,7 +102,7 @@ public GridNodePropertiesPane(boolean isDeletable) { } @Override - protected void doInit(D control) { + protected void doInit(D modelObject) { if (previouslyShownControl != null) { columnIndexSubscription.unsubscribe(); rowIndexSubscription.unsubscribe(); @@ -113,24 +113,24 @@ protected void doInit(D control) { // Column Index columnIndexSubscription = bindBidirectionalWithConverter( - control.columnIndexProperty(), + modelObject.columnIndexProperty(), columnPositionCB.valueProperty(), val -> val - 1, val -> val.intValue() + 1); // Row Index rowIndexSubscription = bindBidirectionalWithConverter( - control.rowIndexProperty(), + modelObject.rowIndexProperty(), rowPositionCB.valueProperty(), val -> val - 1, val -> val.intValue() + 1); // Column Span - previousControlColumnSpanProperty = control.columnSpanProperty().asObject(); + previousControlColumnSpanProperty = modelObject.columnSpanProperty().asObject(); columnSpanCB.valueProperty().bindBidirectional(previousControlColumnSpanProperty); // Row Span - previousControlRowSpanProperty = control.rowSpanProperty().asObject(); + previousControlRowSpanProperty = modelObject.rowSpanProperty().asObject(); rowSpanCB.valueProperty().bindBidirectional(previousControlRowSpanProperty); } } \ No newline at end of file diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java index 36c410016..33ece1817 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PatternPropertiesPane.java @@ -1,7 +1,7 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; -import dev.ikm.komet.kleditorapp.view.control.PatternViewControl; import dev.ikm.komet.kview.controls.ToggleSwitch; +import dev.ikm.komet.layout.editor.model.EditorPatternModel; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.geometry.HPos; @@ -17,7 +17,7 @@ import java.util.List; -public class PatternPropertiesPane extends GridNodePropertiesPane { +public class PatternPropertiesPane extends GridNodePropertiesPane { public static final String DEFAULT_STYLE_CLASS = "pattern-properties"; private final VBox patternMainContainer = new VBox(); @@ -116,19 +116,19 @@ public PatternPropertiesPane() { } @Override - protected void doInit(PatternViewControl control) { - super.doInit(control); + protected void doInit(EditorPatternModel modelObject) { + super.doInit(modelObject); if (previouslyShownControl != null) { columnsComboBox.valueProperty().unbindBidirectional(previousControlColumnsObjProperty); titleVisibleTSwitch.selectedProperty().unbindBidirectional(previouslyShownControl.titleVisibleProperty()); } - titleTextField.setText(control.getTitle()); - titleVisibleTSwitch.selectedProperty().bindBidirectional(control.titleVisibleProperty()); + titleTextField.setText(modelObject.getTitle()); + titleVisibleTSwitch.selectedProperty().bindBidirectional(modelObject.titleVisibleProperty()); // Columns ComboBox - previousControlColumnsObjProperty = control.numberColumnsProperty().asObject(); + previousControlColumnsObjProperty = modelObject.numberColumnsProperty().asObject(); columnsComboBox.valueProperty().bindBidirectional(previousControlColumnsObjProperty); } } \ No newline at end of file diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PropertiesPane.java index d01ef1ed9..94f707c77 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/PropertiesPane.java @@ -6,6 +6,7 @@ import dev.ikm.komet.kleditorapp.view.control.FieldViewControl; import dev.ikm.komet.kleditorapp.view.control.PatternViewControl; import dev.ikm.komet.kleditorapp.view.control.SectionViewControl; +import dev.ikm.komet.kleditorapp.view.control.WindowControlFactory; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.scene.Node; @@ -72,7 +73,7 @@ public void init(SelectionManager selectionManager) { } default -> System.out.println("TODO..."); } - currentPropertiesPane.initControl(control); + currentPropertiesPane.initControl(WindowControlFactory.getModel(control)); }); } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java index cec0f9a4d..191edd40b 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/SectionPropertiesPane.java @@ -1,7 +1,7 @@ package dev.ikm.komet.kleditorapp.view.propertiespane; import dev.ikm.komet.kleditorapp.view.ControlBasePropertiesPane; -import dev.ikm.komet.kleditorapp.view.control.SectionViewControl; +import dev.ikm.komet.layout.editor.model.EditorSectionModel; import javafx.beans.property.ObjectProperty; import javafx.collections.FXCollections; import javafx.geometry.HPos; @@ -17,7 +17,7 @@ import java.util.List; -public class SectionPropertiesPane extends ControlBasePropertiesPane { +public class SectionPropertiesPane extends ControlBasePropertiesPane { public static final String DEFAULT_STYLE_CLASS = "section-properties"; private final VBox sectionMainContainer = new VBox(); @@ -99,7 +99,7 @@ public SectionPropertiesPane() { } @Override - public void doInit(SectionViewControl section) { + public void doInit(EditorSectionModel section) { if (previouslyShownControl != null) { sectionNameTextField.textProperty().unbindBidirectional(previouslyShownControl.nameProperty()); columnsComboBox.valueProperty().unbindBidirectional(lastColumnsSectionProperty); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java index 93ec68257..838cb763b 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/skin/EditorGridPaneSkin.java @@ -172,6 +172,7 @@ private void updateTiles() { if (rowIndex < numberUsedRows) { gridTile = new GridTile(getSkinnable()); } else { + // We add 1 empty Tile below the last one so the user always has an empty row to drag into gridTile = new GridTile(getSkinnable(), true); } diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java index 6ee40a6ff..b5073fd6c 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorFieldModel.java @@ -5,6 +5,8 @@ import dev.ikm.tinkar.entity.FieldDefinitionRecord; import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerWrapper; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.ReadOnlyStringWrapper; import org.slf4j.Logger; @@ -56,6 +58,11 @@ public void save(KometPreferences patternPreferences) { saveGridNodeDetails(fieldPreferences); } + @Override + public void delete() { + getParentPattern().getFields().remove(this); + } + /******************************************************************************* * * * Properties * @@ -82,4 +89,10 @@ public void save(KometPreferences patternPreferences) { private ReadOnlyIntegerWrapper dataTypeNid = new ReadOnlyIntegerWrapper(); public int getDataTypeNid() { return dataTypeNid.get(); } public ReadOnlyIntegerProperty dataTypeNidProperty() { return dataTypeNid.getReadOnlyProperty(); } + + // -- parent Pattern + private ReadOnlyObjectWrapper parentPattern = new ReadOnlyObjectWrapper<>(); + public EditorPatternModel getParentPattern() { return parentPattern.get(); } + public ReadOnlyObjectProperty parentPatternProperty() { return parentPattern.getReadOnlyProperty(); } + void setParentPattern(EditorPatternModel parentPattern) { this.parentPattern.set(parentPattern); } } diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java index ec8f3b4fa..b21f2cfc1 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorGridNodeModel.java @@ -57,4 +57,13 @@ protected void loadGridNodeDetails(KometPreferences preferences) { public int getColumnSpan() { return columnSpan.get(); } public IntegerProperty columnSpanProperty() { return columnSpan; } public void setColumnSpan(int index) { columnSpan.set(index); } + + // -- row span + /** + * The number of rows this Node should span inside the Grid. + */ + private final IntegerProperty rowSpan = new SimpleIntegerProperty(1); + public int getRowSpan() { return rowSpan.get(); } + public IntegerProperty rowSpanProperty() { return rowSpan; } + public void setRowSpan(int index) { rowSpan.set(index); } } \ No newline at end of file diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java index 111733008..21f3ef1d7 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorModelBase.java @@ -1,4 +1,5 @@ package dev.ikm.komet.layout.editor.model; -public class EditorModelBase { +public abstract class EditorModelBase { + public abstract void delete(); } \ No newline at end of file diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java index 4f1ab7e60..277fc0e08 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorPatternModel.java @@ -1,6 +1,5 @@ package dev.ikm.komet.layout.editor.model; -import dev.ikm.komet.preferences.KLEditorPreferences; import dev.ikm.komet.preferences.KometPreferences; import dev.ikm.tinkar.coordinate.stamp.calculator.Latest; import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator; @@ -12,11 +11,14 @@ import dev.ikm.tinkar.terms.PatternFacade; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import org.eclipse.collections.api.list.ImmutableList; import org.slf4j.Logger; @@ -57,6 +59,8 @@ public EditorPatternModel(ViewCalculator viewCalculator, int patternNid) { setTitle(retrieveDisplayName(patternFacade)); + fields.addListener(this::fieldsChanged); + // -- add fields if they exist Entity entity = EntityService.get().getEntityFast(patternFacade); Latest optionalLatest = viewCalculator.latest(entity); @@ -70,7 +74,14 @@ public EditorPatternModel(ViewCalculator viewCalculator, int patternNid) { editorFieldModel.setRowIndex(fields.indexOf(editorFieldModel)); }); }); + } + private void fieldsChanged(ListChangeListener.Change change) { + while (change.next()) { + if (change.wasAdded()) { + change.getAddedSubList().forEach(field -> field.setParentPattern(this)); + } + } } /** @@ -158,6 +169,11 @@ private String retrieveDisplayName(PatternFacade patternFacade) { return optionalStringRegularName.orElseGet(optionalStringFQN::get); } + @Override + public void delete() { + getParentSection().getPatterns().remove(this); + } + /******************************************************************************* * * * Properties * @@ -200,4 +216,10 @@ private String retrieveDisplayName(PatternFacade patternFacade) { public int getNumberColumns() { return numberColumns.get(); } public IntegerProperty numberColumnsProperty() { return numberColumns; } public void setNumberColumns(int number) { numberColumns.set(number); } + + // -- parent section + private ReadOnlyObjectWrapper parentSection = new ReadOnlyObjectWrapper<>(); + public EditorSectionModel getParentSection() { return parentSection.get(); } + public ReadOnlyObjectProperty parentSectionProperty() { return parentSection.getReadOnlyProperty(); } + void setParentSection(EditorSectionModel parentSection) { this.parentSection.set(parentSection); } } diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java index 5e38eaed3..3a77d1a5a 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorSectionModel.java @@ -3,10 +3,13 @@ import dev.ikm.komet.preferences.KometPreferences; import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator; import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +30,10 @@ public class EditorSectionModel extends EditorModelBase { public static final String UNTITLED_SECTION_NAME = "Untitled"; + public EditorSectionModel() { + patterns.addListener(this::patternsChanged); + } + /******************************************************************************* * * * Public API * @@ -88,6 +95,25 @@ public void save(KometPreferences editorWindowPreferences) { } } + @Override + public void delete() { + getParentWindow().getAdditionalSections().remove(this); + } + + /******************************************************************************* + * * + * Private Implementation * + * * + ******************************************************************************/ + + private void patternsChanged(ListChangeListener.Change change) { + while(change.next()) { + if (change.wasAdded()) { + change.getAddedSubList().forEach(pattern -> pattern.setParentSection(this)); + } + } + } + private void saveSectionDetails(KometPreferences editorWindowPreferences) { final KometPreferences sectionPreferences = editorWindowPreferences.node(getName()); @@ -143,4 +169,10 @@ private void saveSectionDetails(KometPreferences editorWindowPreferences) { public int getNumberColumns() { return numberColumns.get(); } public IntegerProperty numberColumnsProperty() { return numberColumns; } public void setNumberColumns(int number) { numberColumns.set(number); } + + // -- parent window + ReadOnlyObjectWrapper parentWindow = new ReadOnlyObjectWrapper<>(); + public EditorWindowModel getParentWindow() { return parentWindow.get(); } + public ReadOnlyObjectProperty parentWindowProperty() { return parentWindow; } + void setParentWindow(EditorWindowModel editorWindowModel) { parentWindow.set(editorWindowModel); } } \ No newline at end of file diff --git a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorWindowModel.java b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorWindowModel.java index d4095603e..57148dfaf 100644 --- a/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorWindowModel.java +++ b/knowledge-layout/src/main/java/dev/ikm/komet/layout/editor/model/EditorWindowModel.java @@ -49,6 +49,7 @@ public EditorWindowModel() { */ public static EditorWindowModel load(KometPreferences editorWindowPreferences, ViewCalculator viewCalculator, String title) { EditorWindowModel editorWindowModel = new EditorWindowModel(); + editorWindowModel.setTitle(title); editorWindowModel.loadMainSection(editorWindowPreferences, viewCalculator); @@ -138,6 +139,9 @@ private void additionalSectionsChanged(ListChangeListener.Change Date: Tue, 20 Jan 2026 14:34:25 +0000 Subject: [PATCH 11/15] FVKB-130: Add the ability to tweak Field visibility on or off --- .../kleditorapp/view/KLEditorWindowController.java | 12 ++++++++++-- .../view/propertiespane/FieldPropertiesPane.java | 2 +- .../view/genpurpose/GenPurposeDetailsController.java | 7 +++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java index dfe6796ca..d15b42f40 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorWindowController.java @@ -102,17 +102,25 @@ private void addPatternView(EditorSectionModel editorSectionModel, EditorPattern PatternViewControl patternViewControl = WindowControlFactory.createPatternView(patternModel); addFieldViews(patternModel, patternModel.getFields()); - patternModel.getFields().addListener((ListChangeListener) change -> onPatternModelFieldsChanged(patternModel, change)); + patternModel.getFields().addListener( + (ListChangeListener) change -> onPatternModelFieldsChanged(patternModel, patternViewControl, change)); SectionViewControl sectionViewControl = (SectionViewControl) WindowControlFactory.getView(editorSectionModel); sectionViewControl.getPatterns().add(patternViewControl); } - private void onPatternModelFieldsChanged(EditorPatternModel patternModel, ListChangeListener.Change change) { + private void onPatternModelFieldsChanged(EditorPatternModel patternModel, PatternViewControl patternViewControl, + ListChangeListener.Change change) { while(change.next()) { if (change.wasAdded()) { addFieldViews(patternModel, change.getAddedSubList()); } + if (change.wasRemoved()) { + change.getRemoved().forEach(fieldModel -> { + FieldViewControl fieldViewControl = (FieldViewControl) WindowControlFactory.getView(fieldModel); + patternViewControl.getFields().remove(fieldViewControl); + }); + } } } diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java index be0a78751..fa81377f6 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/propertiespane/FieldPropertiesPane.java @@ -41,7 +41,7 @@ public class FieldPropertiesPane extends GridNodePropertiesPane displayComboBox; public FieldPropertiesPane() { - super(false); + super(true); VBox titleContainer = new VBox(); titleContainer.getStyleClass().add("title-container"); diff --git a/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java b/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java index 69f450226..4835ccc82 100644 --- a/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java +++ b/kview/src/main/java/dev/ikm/komet/kview/mvvm/view/genpurpose/GenPurposeDetailsController.java @@ -617,8 +617,11 @@ private List createFieldViews(EditorPatternModel editorPa ObservableEntitySnapshot snap = composer.snapshot(semantic.nid()).get(); if (snap instanceof ObservableSemanticSnapshot semanticSnapshot) { for(ObservableField observableField : semanticSnapshot.getLatestFields().get()){ - EditorFieldModel fieldModel = editorPatternModel.getFields().get(observableField.field().indexInPattern()); - createFieldView(observableField, fieldModel, controlItems, fieldsContainer); + for (EditorFieldModel editorFieldModel : editorPatternModel.getFields()) { + if (observableField.field().indexInPattern() == editorFieldModel.getIndex()) { + createFieldView(observableField, editorFieldModel, controlItems, fieldsContainer); + } + } } } From 4b6540467aa541c2524bf40150b495a3a24aacea Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Wed, 21 Jan 2026 00:00:46 +0000 Subject: [PATCH 12/15] UI tweaks: Add hover and armed effects to buttons --- .../dev/ikm/komet/kleditorapp/view/kl-core.css | 11 ++++++++++- .../ikm/komet/kleditorapp/view/kl-editor-window.css | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css index 3a7683499..d48dab318 100644 --- a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css +++ b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-core.css @@ -90,13 +90,22 @@ -fx-padding: 0.25em 0.833333em 0.25em 0.833333em; /* 4 10 4 10 */ } + +.button:hover { + -fx-background-color: derive(-Grey-2, -5%); +} + /* Dark */ .button.dark { -fx-background-color: -Grey-11; } .button.dark:hover { - -fx-background-color: derive(-Grey-11, 5%); + -fx-background-color: derive(-Grey-11, 15%); +} + +.button.dark:hover:armed { + -fx-background-color: -Grey-11; } /* Default */ diff --git a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css index 0a58c1384..f2937ecac 100644 --- a/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css +++ b/knowledge-layout-editor/src/main/resources/dev/ikm/komet/kleditorapp/view/kl-editor-window.css @@ -291,6 +291,16 @@ -fx-graphic-text-gap: 10px; } +.add-section.button:hover { + -fx-background-color: #f0f0f0; + -fx-border-color: #f0f0f0; +} + +.add-section.button:armed { + -fx-background-color: #e8e8e8; + -fx-border-color: #e8e8e8; +} + .add-section.button .icon { -fx-background-color: #4a7ad2; } \ No newline at end of file From caa9283abe152d53d9527c494e0658eeb7d2172d Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Thu, 22 Jan 2026 16:49:17 +0000 Subject: [PATCH 13/15] FVKB-158: Sort Patterns in Pattern Browser in KL Editor alphabetically --- .../view/KLEditorMainScreenController.java | 19 +++++++--- .../kleditorapp/view/PatternBrowserItem.java | 38 +++++++++++++++++++ .../view/control/PatternBrowserCell.java | 22 ++++------- 3 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/PatternBrowserItem.java diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java index e251dfdca..94b1fc071 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java @@ -31,6 +31,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Comparator; + import static dev.ikm.komet.kview.events.EventTopics.KL_TOPIC; import static dev.ikm.komet.preferences.KLEditorPreferences.KL_EDITOR_APP; @@ -49,7 +51,7 @@ public class KLEditorMainScreenController { private TextField titleTextField; @FXML - private ListView patternBrowserListView; + private ListView patternBrowserListView; private KLEditorWindowController klEditorWindowController; @@ -64,7 +66,7 @@ public class KLEditorMainScreenController { private ObservableViewNoOverride windowViewCoordinates; private ViewCalculator viewCalculator; - private ObservableList> patterns; + private ObservableList patternsList; public void init(KometPreferences klEditorAppPreferences, WindowSettings windowSettings, String windowToLoad) { this.klEditorAppPreferences = klEditorAppPreferences; @@ -99,18 +101,25 @@ public void shutdown() { } private void initPatternsList(ViewCalculator viewCalculator) { - patterns = FXCollections.observableArrayList(); + patternsList = FXCollections.observableArrayList(); PrimitiveData.get().forEachPatternNid(patternNid -> { Latest latestPattern = viewCalculator.latest(patternNid); latestPattern.ifPresent(patternEntityVersion -> { if (EntityService.get().getEntity(patternEntityVersion.nid()).isPresent()) { - patterns.add(EntityService.get().getEntity(patternNid).get()); + Entity entity = EntityService.get().getEntity(patternNid).get(); + PatternBrowserItem patternBrowserItem = new PatternBrowserItem(entity, viewCalculator); + patternsList.add(patternBrowserItem); } }); }); + // Sort + FXCollections.sort(patternsList, + Comparator.comparing(PatternBrowserItem::getTitle, + String.CASE_INSENSITIVE_ORDER)); + patternBrowserListView.setCellFactory(param -> new PatternBrowserCell(viewCalculator)); - patternBrowserListView.setItems(patterns); + patternBrowserListView.setItems(patternsList); } private void initWindow(String windowTitle) { diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/PatternBrowserItem.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/PatternBrowserItem.java new file mode 100644 index 000000000..974fdeb64 --- /dev/null +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/PatternBrowserItem.java @@ -0,0 +1,38 @@ +package dev.ikm.komet.kleditorapp.view; + +import dev.ikm.tinkar.common.id.PublicId; +import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator; +import dev.ikm.tinkar.entity.Entity; +import dev.ikm.tinkar.entity.EntityVersion; +import dev.ikm.tinkar.terms.PatternFacade; + +import java.util.Optional; + +/** + * Represents an Item in the Pattern Browser List. + */ +public class PatternBrowserItem { + private final String title; + private final PublicId publicId; + private final int nid; + + private final ViewCalculator viewCalculator; + + public PatternBrowserItem(Entity entity, ViewCalculator viewCalculator) { + this.viewCalculator = viewCalculator; + + this.title = retrieveDisplayName(entity.toProxy()); + this.publicId = entity.publicId(); + this.nid = entity.nid(); + } + + private String retrieveDisplayName(PatternFacade patternFacade) { + Optional optionalStringRegularName = viewCalculator.getRegularDescriptionText(patternFacade); + Optional optionalStringFQN = viewCalculator.getFullyQualifiedNameText(patternFacade); + return optionalStringRegularName.orElseGet(optionalStringFQN::get); + } + + public String getTitle() { return title; } + public PublicId getPublicId() { return publicId; } + public int getNid() { return nid; } +} diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternBrowserCell.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternBrowserCell.java index dfc057a64..f7d66d525 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternBrowserCell.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/PatternBrowserCell.java @@ -3,13 +3,11 @@ import dev.ikm.komet.framework.Identicon; import dev.ikm.komet.framework.controls.TimeUtils; import dev.ikm.komet.framework.dnd.DragImageMaker; +import dev.ikm.komet.kleditorapp.view.PatternBrowserItem; import dev.ikm.tinkar.coordinate.stamp.calculator.Latest; import dev.ikm.tinkar.coordinate.view.calculator.ViewCalculator; -import dev.ikm.tinkar.entity.Entity; -import dev.ikm.tinkar.entity.EntityVersion; import dev.ikm.tinkar.entity.PatternEntityVersion; import dev.ikm.tinkar.entity.StampEntity; -import dev.ikm.tinkar.terms.PatternFacade; import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.control.ListCell; @@ -31,7 +29,7 @@ /** * A Cell that renders each item in the Pattern Browser List. */ -public class PatternBrowserCell extends ListCell> { +public class PatternBrowserCell extends ListCell { private static final Logger LOG = LoggerFactory.getLogger(PatternBrowserCell.class); public static final DataFormat KL_EDITOR_VERSION_PROXY = new DataFormat("kl-editor/komet-pattern-version-proxy"); @@ -91,17 +89,17 @@ public PatternBrowserCell(ViewCalculator viewCalculator) { } @Override - protected void updateItem(Entity entity, boolean empty) { - super.updateItem(entity, empty); + protected void updateItem(PatternBrowserItem patternBrowserItem, boolean empty) { + super.updateItem(patternBrowserItem, empty); if (!isEmpty()) { - Latest optionalLatestPattern = viewCalculator.latest(entity.nid()); + Latest optionalLatestPattern = viewCalculator.latest(patternBrowserItem.getNid()); optionalLatestPattern.ifPresentOrElse(latestPattern -> { // Title - titleLabel.setText(retrieveDisplayName(entity.toProxy())); + titleLabel.setText(patternBrowserItem.getTitle()); // Identicon - Image identiconImage = Identicon.generateIdenticonImage(entity.publicId()); + Image identiconImage = Identicon.generateIdenticonImage(patternBrowserItem.getPublicId()); identiconImageView.setImage(identiconImage); currentPatternEntityVersion = latestPattern; @@ -133,12 +131,6 @@ private void clearCellsContent() { lastUpdatedTextLabel.setText(""); } - private String retrieveDisplayName(PatternFacade patternFacade) { - Optional optionalStringRegularName = viewCalculator.getRegularDescriptionText(patternFacade); - Optional optionalStringFQN = viewCalculator.getFullyQualifiedNameText(patternFacade); - return optionalStringRegularName.orElseGet(optionalStringFQN::get); - } - private void setUpDragAndDrop() { // Set up the drag detection event handler setOnDragDetected(mouseEvent -> { From e7d414904ae77cadaa1bd83085b82872be0742f0 Mon Sep 17 00:00:00 2001 From: Pedro Duque Vieira Date: Thu, 22 Jan 2026 20:23:09 +0000 Subject: [PATCH 14/15] FVKB-159: Remove UI clutter and make the UI more intuitive --- .../view/KLEditorMainScreenController.java | 5 +++ .../view/control/EditorWindowControl.java | 2 +- .../kleditorapp/view/KLEditorMainScreen.fxml | 34 +++---------------- .../ikm/komet/kleditorapp/view/kl-editor.css | 21 +++++++++--- .../layout/editor/EditorWindowManager.java | 1 - .../editor/model/EditorWindowModel.java | 4 +-- .../dev/ikm/komet/kview/mvvm/view/kview.css | 3 +- 7 files changed, 30 insertions(+), 40 deletions(-) diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java index 94b1fc071..58b79c9d6 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/KLEditorMainScreenController.java @@ -25,6 +25,7 @@ import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.control.TextField; import javafx.scene.layout.BorderPane; @@ -41,6 +42,9 @@ public class KLEditorMainScreenController { private final EvtBus eventBus = EvtBusFactory.getDefaultEvtBus(); + @FXML + private Button saveButton; + @FXML private PropertiesPane propertiesPane; @@ -77,6 +81,7 @@ public void init(KometPreferences klEditorAppPreferences, WindowSettings windowS viewCalculator = ViewCalculatorWithCache.getCalculator(windowViewCoordinates.toViewCoordinateRecord()); initPatternsList(viewCalculator); + saveButton.disableProperty().bind(titleTextField.textProperty().isEmpty()); // Init Window initWindow(windowToLoad); diff --git a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/EditorWindowControl.java b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/EditorWindowControl.java index 1c0cc0017..fc4535ef9 100644 --- a/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/EditorWindowControl.java +++ b/knowledge-layout-editor/src/main/java/dev/ikm/komet/kleditorapp/view/control/EditorWindowControl.java @@ -37,7 +37,7 @@ private void onSectionsChanged(ListChangeListener.Change