Skip to content

Commit 37bcb1a

Browse files
committed
#204: Improve the aesthetics of the Pattern Browser
1 parent dc3207f commit 37bcb1a

7 files changed

Lines changed: 157 additions & 17 deletions

File tree

‎framework/src/main/java/dev/ikm/komet/framework/controls/KonceptBadge.java‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ public enum PopoutPosition {
256256
private PremiseType premiseType = PremiseType.INFERRED;
257257
private KonceptStatus status = KonceptStatus.NONE;
258258
private KonceptKind kind = KonceptKind.CONCEPT;
259+
/** See {@link #setKindSigilShown}. */
260+
private boolean kindSigilShown = true;
259261
/** Letter-sigil size (px), {@link #SIGIL_TO_NAME} of the current name font. */
260262
private double letterSigilSize = SC_FONT_SIZE * SIGIL_TO_NAME;
261263
/** Pentagon edge (px), {@link #PENTAGON_TO_ICON} of the current identicon edge. */
@@ -712,11 +714,25 @@ public final void setKind(KonceptKind kind) {
712714
}
713715

714716
/**
715-
* Shows the sigil slot when the kind has a sigil and the glyph settings show sigils
716-
* (ikmdev/komet-desktop#153); an empty or hidden slot collapses so it opens no gap.
717+
* Whether this badge shows its kind sigil at all, on top of the glyph settings: a surface that
718+
* lists one kind only (the pattern browser lists patterns and nothing else) turns it off, since
719+
* the letter would say nothing there. On by default. The drag glyph keeps the sigil either way:
720+
* dragged into a surface that mixes kinds, the badge states its kind again.
721+
*
722+
* @param shown {@code false} hides the sigil on this badge; {@code true} leaves it to the settings
723+
*/
724+
public final void setKindSigilShown(boolean shown) {
725+
this.kindSigilShown = shown;
726+
applySigilVisibility();
727+
}
728+
729+
/**
730+
* Shows the sigil slot when the kind has a sigil, the glyph settings show sigils
731+
* (ikmdev/komet-desktop#153) and the badge {@link #setKindSigilShown shows it}; an empty or
732+
* hidden slot collapses so it opens no gap.
717733
*/
718734
private void applySigilVisibility() {
719-
boolean visible = kind.hasSigil() && showKindSigil.getValue();
735+
boolean visible = kind.hasSigil() && showKindSigil.getValue() && kindSigilShown;
720736
sigilBox.setManaged(visible);
721737
sigilBox.setVisible(visible);
722738
}

‎framework/src/test/java/dev/ikm/komet/framework/controls/KonceptBadgeKindUTestFX.java‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,24 @@ void settingKindBackToConceptClearsTheSigil() {
104104
assertFalse(badge.isConceptViolation());
105105
}
106106

107+
@Test
108+
void aBadgeCanHideItsSigilWhereTheKindIsAGiven() {
109+
KonceptBadge badge = badge();
110+
badge.setKind(KonceptKind.PATTERN);
111+
assertTrue(sigilBox(badge).isManaged(), "a pattern shows its P by default");
112+
113+
// A surface listing one kind only (the pattern browser) turns the sigil off; the kind and
114+
// its sigil node stay, so the badge still drags with its P.
115+
badge.setKindSigilShown(false);
116+
assertFalse(sigilBox(badge).isManaged(), "the hidden slot collapses");
117+
assertFalse(sigilBox(badge).isVisible());
118+
assertEquals(KonceptKind.PATTERN, badge.getKind());
119+
assertFalse(sigilBox(badge).getChildrenUnmodifiable().isEmpty(), "the sigil node is kept");
120+
121+
badge.setKindSigilShown(true);
122+
assertTrue(sigilBox(badge).isManaged(), "shown again, the settings decide");
123+
}
124+
107125
@Test
108126
void alarmTriggersOnlyForANonConceptInAConceptExpectingContext() {
109127
KonceptBadge badge = badge();

‎kview/src/main/java/dev/ikm/komet/kview/mvvm/view/navigation/ConceptPatternNavController.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ public static VBox createPatternsPanel(Node searchTextField, ScrollPane patternL
435435
StackPane searchContainer = new StackPane(searchTextField);
436436
searchContainer.getStyleClass().add("pattern-navigation-search");
437437
VBox panel = new VBox(searchContainer, patternList);
438+
panel.getStyleClass().add("pattern-browser");
438439
VBox.setVgrow(patternList, Priority.ALWAYS);
439440
return panel;
440441
}

‎kview/src/main/java/dev/ikm/komet/kview/mvvm/view/navigation/PatternNavEntryController.java‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ private void initialize() {
177177
// to the raw nid and the row would read "-2147477853".
178178
patternBadge.setConceptName(
179179
ViewCalculatorUtils.retrieveDisplayName((PatternFacade) patternFacade, vProperties));
180+
// The browser lists patterns and nothing else, so the P sigil would only repeat the column's
181+
// title; the badge still drags with it, into surfaces that mix kinds.
182+
patternBadge.setKindSigilShown(false);
180183
// Sized to this row rather than the badge's inline default, which is scaled for sitting
181184
// beside body text and renders far too small in a navigation list. The badge sets its
182185
// fonts in code, so the stylesheet's root size cannot reach it: the row follows the text
@@ -331,8 +334,10 @@ public boolean hasFilterMatches() {
331334

332335
private void updateListViewPrefHeight() {
333336
int itemsNumber = patternInstancesListView.getItems().size();
334-
/* adding a number to LIST_VIEW_CELL_SIZE to account for padding, etc */
335-
double newPrefHeight = itemsNumber * (LIST_VIEW_CELL_SIZE + 10);
337+
// The rows plus the list's own insets, so the list is exactly as tall as its content: any
338+
// slack shows as a blank band, and any shortfall as a scrollbar.
339+
double newPrefHeight = itemsNumber * LIST_VIEW_CELL_SIZE
340+
+ patternInstancesListView.snappedTopInset() + patternInstancesListView.snappedBottomInset();
336341
double maxHeight = patternInstancesListView.getMaxHeight();
337342

338343
patternInstancesListView.setPrefHeight(Math.min(newPrefHeight, maxHeight));

‎kview/src/main/java/dev/ikm/komet/kview/mvvm/view/navigation/PatternSemanticListCell.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ public PatternSemanticListCell(Function<Long, String> fetchDescriptionByNid,
5050
this.viewProperties = viewProperties;
5151

5252
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
53+
// The row takes the list's width rather than asking for its content's: a long title would
54+
// otherwise widen the list and bring in a horizontal scrollbar, which steals height and
55+
// then a vertical one.
56+
setPrefWidth(0);
5357

5458
label = new Label();
5559
label.setMaxWidth(Double.MAX_VALUE);

‎kview/src/main/resources/dev/ikm/komet/kview/mvvm/view/kview.css‎

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,12 +3765,10 @@ Timeline Year line segment (will overlay change circles)
37653765
-fx-graphic-text-gap: 9px;
37663766
}
37673767

3768+
/* The row's title takes the width the row gives it (it grows in the row and ellipsizes); a fixed
3769+
354px here used to overflow the browser's tiles and bring in a horizontal scrollbar. */
37683770
.pattern-instance-hbox .pattern-instance {
3769-
width: 354px;
3770-
3771-
-fx-min-width: width;
3772-
-fx-pref-width: width;
3773-
-fx-max-width: width;
3771+
-fx-min-width: 0;
37743772

37753773
-fx-padding: 0 10 0 0;
37763774

@@ -5530,9 +5528,14 @@ Styling a context menu for kview ui/ux controls
55305528

55315529
/* Pattern Browser ScrollPane */
55325530

5531+
/* The PATTERNS side of the navigator: a light column (the mockup's), the scroll pane showing it through. */
5532+
.pattern-browser {
5533+
-fx-background-color: #E7EBF1;
5534+
}
5535+
55335536
.pattern-navigation-scroll-pane,
55345537
.pattern-navigation-scroll-pane > .viewport {
5535-
-fx-background-color: #545d72;
5538+
-fx-background-color: transparent;
55365539
}
55375540

55385541
.pattern-navigation-scroll-pane > .scroll-bar:vertical {
@@ -5556,8 +5559,59 @@ Styling a context menu for kview ui/ux controls
55565559
}
55575560

55585561
.pattern-navigation-container {
5559-
-fx-spacing: 4px;
5560-
-fx-padding: 0 2px 0 12px;
5562+
-fx-spacing: 6px;
5563+
-fx-padding: 0 2px 8px 12px;
5564+
}
5565+
5566+
/* A pattern card: white, a hairline border, softly rounded. */
5567+
.pattern-instance-container {
5568+
-fx-background-color: white;
5569+
-fx-background-radius: 3px;
5570+
-fx-border-color: -Grey-5;
5571+
-fx-border-width: 1;
5572+
-fx-border-radius: 3px;
5573+
}
5574+
5575+
/* The card's SEMANTIC ELEMENTS pane: one thin blue rounded frame around the bar and, when
5576+
expanded, the light wash the instance rows sit on. Scoped to the browser — the same titled-pane
5577+
class also dresses the next-gen search's result entries, which keep their look. */
5578+
.pattern-browser .search-entry-title-pane {
5579+
-fx-border-color: -Secondary-05;
5580+
-fx-border-width: 1;
5581+
-fx-border-radius: 4px;
5582+
-fx-background-color: transparent;
5583+
-fx-background-radius: 4px;
5584+
}
5585+
5586+
.pattern-browser .titled-pane.search-entry-title-pane > .title {
5587+
-fx-background-color: white;
5588+
-fx-background-radius: 4px;
5589+
-fx-padding: 5 8 5 8;
5590+
}
5591+
5592+
.pattern-browser .titled-pane.search-entry-title-pane:expanded > .title {
5593+
-fx-background-radius: 4px 4px 0 0;
5594+
}
5595+
5596+
.pattern-browser .titled-pane.search-entry-title-pane > .title > .arrow-button .arrow {
5597+
-fx-background-color: -Secondary-05;
5598+
}
5599+
5600+
.pattern-browser .titled-pane.search-entry-title-pane > .title > .text {
5601+
-fx-fill: -Grey-9;
5602+
-fx-background-color: transparent;
5603+
}
5604+
5605+
/* Expanding a card used to wrap it in a 3px blue frame on a grey wash; here the card stays a white
5606+
card and only the pane below the bar takes the wash. */
5607+
.pattern-browser .search-entry-title-pane-pattern {
5608+
-fx-border-width: 0;
5609+
-fx-background-color: transparent;
5610+
}
5611+
5612+
.pattern-browser .search-entry-title-pane > .content {
5613+
-fx-background-color: -Grey-2;
5614+
-fx-background-radius: 0 0 4px 4px;
55615615
}
55625616

55635617
/* The reference-component search over the pattern list (a ComponentSearchTextField, styled with the

‎kview/src/test/java/dev/ikm/komet/kview/mvvm/view/navigation/test/PatternBrowserSearchUTestFX.java‎

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@
2323
import dev.ikm.tinkar.common.service.ServiceKeys;
2424
import dev.ikm.tinkar.common.service.ServiceProperties;
2525
import dev.ikm.tinkar.coordinate.Calculators;
26+
import javafx.geometry.Insets;
2627
import javafx.scene.Scene;
28+
import javafx.scene.control.ContentDisplay;
29+
import javafx.scene.control.Label;
30+
import javafx.scene.control.ListView;
2731
import javafx.scene.control.ScrollPane;
2832
import javafx.scene.control.TextField;
33+
import javafx.scene.control.TitledPane;
34+
import javafx.scene.layout.HBox;
35+
import javafx.scene.layout.Priority;
2936
import javafx.scene.layout.Region;
3037
import javafx.scene.layout.VBox;
3138
import org.junit.jupiter.api.AfterAll;
@@ -74,18 +81,23 @@ void showBrowser() throws Exception {
7481
FxToolkit.setupStage(stage -> {
7582
ComponentSearchTextField searchTextField = KLComponentControlFactory.createComponentSearchTextField(Calculators.View.Default());
7683
searchTextField.setPromptText("Search instances by component");
77-
// A list far taller than the column, as the real browser's is: the search row must not
78-
// be squeezed to make room for it.
84+
// Two stand-in cards in the entry FXML's shape (pattern-nav-entry.fxml), one expanded with
85+
// a filter count, to see the browser's card styling — then a list far taller than the
86+
// column, as the real browser's is: the search row must not be squeezed to make room.
87+
VBox cards = new VBox(card("Description Pattern", true), card("Identifier Pattern", false));
88+
cards.getStyleClass().add("pattern-navigation-container");
7989
Region tallList = new Region();
8090
tallList.setPrefHeight(4000);
81-
ScrollPane patternList = new ScrollPane(tallList);
91+
cards.getChildren().add(tallList);
92+
ScrollPane patternList = new ScrollPane(cards);
93+
patternList.setFitToWidth(true);
8294
patternList.getStyleClass().add("pattern-navigation-scroll-pane");
8395
VBox patternsPanel = ConceptPatternNavController.createPatternsPanel(searchTextField, patternList);
8496
column = new VBox(patternsPanel);
8597
column.getStyleClass().addAll("concept-pattern-container", "grey-vertical-scroll-area");
8698
column.getStylesheets().add(ComponentSearchTextField.class
8799
.getResource("/dev/ikm/komet/kview/mvvm/view/kview.css").toExternalForm());
88-
stage.setScene(new Scene(column, 430, 300));
100+
stage.setScene(new Scene(column, 430, 420));
89101
stage.show();
90102
});
91103
FxToolkit.setupFixture(() -> column.applyCss());
@@ -96,6 +108,36 @@ void hideBrowser() throws Exception {
96108
FxToolkit.cleanupStages();
97109
}
98110

111+
/** A pattern card as pattern-nav-entry.fxml and PatternNavEntryController build one, by style class. */
112+
private static HBox card(String name, boolean expanded) {
113+
Label title = new Label(name);
114+
HBox titleRow = new HBox(title);
115+
titleRow.getStyleClass().add("pattern-title-container");
116+
117+
ListView<String> instances = new ListView<>();
118+
instances.getStyleClass().add("pattern-instances-list-view");
119+
instances.setPrefHeight(90);
120+
TitledPane pane = new TitledPane("SEMANTIC ELEMENTS", instances);
121+
pane.getStyleClass().add("search-entry-title-pane");
122+
pane.setAnimated(false);
123+
VBox.setMargin(pane, new Insets(0, 8, 8, 8));
124+
125+
VBox main = new VBox(titleRow, pane);
126+
if (expanded) {
127+
main.getStyleClass().add("search-entry-title-pane-pattern");
128+
Label count = new Label("3");
129+
count.getStyleClass().add("semantic-elements-count");
130+
pane.setContentDisplay(ContentDisplay.RIGHT);
131+
pane.setGraphic(count);
132+
}
133+
pane.setExpanded(expanded);
134+
135+
HBox card = new HBox(main);
136+
HBox.setHgrow(main, Priority.ALWAYS);
137+
card.getStyleClass().addAll("search-entry-hbox", "pattern-instance-container");
138+
return card;
139+
}
140+
99141
@Test
100142
@DisplayName("The search field takes the box styling (30px tall) and renders to target/pattern-browser-search/search.png")
101143
void searchFieldIsStyled() {

0 commit comments

Comments
 (0)