diff --git a/CHANGELOG.md b/CHANGELOG.md index a888ad3..3619b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - (CSS) 🚀 New MacOS-like Cupertino theme in light and dark variants. - (CSS) 🚀 New [Dracula](https://ui.draculatheme.com/) theme. +- (CSS) 🚀 New `TabPane` style. There are three styles supported: default, floating and classic (new one). ### Improvements diff --git a/base/src/main/java/atlantafx/base/theme/Styles.java b/base/src/main/java/atlantafx/base/theme/Styles.java index f3f6a4f..34a85bb 100644 --- a/base/src/main/java/atlantafx/base/theme/Styles.java +++ b/base/src/main/java/atlantafx/base/theme/Styles.java @@ -4,6 +4,7 @@ package atlantafx.base.theme; import javafx.css.PseudoClass; import javafx.scene.Node; +import javafx.scene.control.TabPane; @SuppressWarnings("unused") public final class Styles { @@ -54,6 +55,9 @@ public final class Styles { public static final String ROUNDED = "rounded"; public static final String STRIPED = "striped"; + public static final String TABS_CLASSIC = "classic"; + public static final String TABS_FLOATING = TabPane.STYLE_CLASS_FLOATING; + // Text public static final String TITLE_1 = "title-1"; diff --git a/docs/docs/reference/controls.md b/docs/docs/reference/controls.md index 2ba6bf8..1a926fd 100644 --- a/docs/docs/reference/controls.md +++ b/docs/docs/reference/controls.md @@ -245,7 +245,10 @@ Color variables: CSS classes: * `.dense` -* `.floating` (`TabPane.STYLE_CLASS_FLOATING`) +* `.floating` (`TabPane.STYLE_CLASS_FLOATING` or `Styles.TABS_FLOATING`) +* `.classic` (`Styles.TABS_CLASSIC`) + +Floating and classic styles are mutually exclusive. ## Titled Pane diff --git a/sampler/src/main/java/atlantafx/sampler/page/components/TabPanePage.java b/sampler/src/main/java/atlantafx/sampler/page/components/TabPanePage.java index 50458e5..acfdb32 100644 --- a/sampler/src/main/java/atlantafx/sampler/page/components/TabPanePage.java +++ b/sampler/src/main/java/atlantafx/sampler/page/components/TabPanePage.java @@ -14,6 +14,7 @@ import atlantafx.base.controls.ToggleSwitch; import atlantafx.base.theme.Styles; import atlantafx.sampler.page.AbstractPage; import atlantafx.sampler.page.SampleBlock; +import java.util.List; import javafx.application.Platform; import javafx.collections.ListChangeListener; import javafx.geometry.Pos; @@ -23,6 +24,8 @@ import javafx.scene.control.Label; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TitledPane; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.ToggleGroup; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; @@ -71,6 +74,7 @@ public class TabPanePage extends AbstractPage { setUserContent(new SampleBlock("Playground", root)); } + @SuppressWarnings("unchecked") private TitledPane createController(BorderPane borderPane, TabPane tabs) { // == BUTTONS == @@ -123,13 +127,6 @@ public class TabPanePage extends AbstractPage { } }); - var floatingToggle = new ToggleSwitch(); - floatingToggle.selectedProperty().addListener((obs, old, val) -> { - if (val != null) { - Styles.toggleStyleClass(tabs, TabPane.STYLE_CLASS_FLOATING); - } - }); - var animatedToggle = new ToggleSwitch(); animatedToggle.setSelected(true); animatedToggle.selectedProperty().addListener((obs, old, val) -> { @@ -165,20 +162,48 @@ public class TabPanePage extends AbstractPage { togglesGrid.add(createGridLabel("Closeable"), 0, 0); togglesGrid.add(closeableToggle, 1, 0); - togglesGrid.add(createGridLabel("Floating"), 0, 1); - togglesGrid.add(floatingToggle, 1, 1); + togglesGrid.add(createGridLabel("Animated"), 0, 1); + togglesGrid.add(animatedToggle, 1, 1); - togglesGrid.add(createGridLabel("Animated"), 0, 2); - togglesGrid.add(animatedToggle, 1, 2); + togglesGrid.add(createGridLabel("Full width"), 0, 2); + togglesGrid.add(fullWidthToggle, 1, 2); - togglesGrid.add(createGridLabel("Full width"), 0, 3); - togglesGrid.add(fullWidthToggle, 1, 3); + togglesGrid.add(createGridLabel("Dense"), 0, 3); + togglesGrid.add(denseToggle, 1, 3); - togglesGrid.add(createGridLabel("Dense"), 0, 4); - togglesGrid.add(denseToggle, 1, 4); + togglesGrid.add(createGridLabel("Disable"), 0, 4); + togglesGrid.add(disableToggle, 1, 4); - togglesGrid.add(createGridLabel("Disable"), 0, 5); - togglesGrid.add(disableToggle, 1, 5); + // == TAB STYLE == + + var styleToggleGroup = new ToggleGroup(); + + var defaultStyleToggle = new ToggleButton("Default"); + defaultStyleToggle.setToggleGroup(styleToggleGroup); + defaultStyleToggle.setUserData(List.of("whatever", Styles.TABS_FLOATING, Styles.TABS_CLASSIC)); + defaultStyleToggle.getStyleClass().add(Styles.LEFT_PILL); + defaultStyleToggle.setSelected(true); + + var floatingStyleToggle = new ToggleButton("Floating"); + floatingStyleToggle.setToggleGroup(styleToggleGroup); + floatingStyleToggle.setUserData(List.of(Styles.TABS_FLOATING, "whatever", Styles.TABS_CLASSIC)); + floatingStyleToggle.getStyleClass().add(Styles.CENTER_PILL); + + var classicStyleToggle = new ToggleButton("Classic"); + classicStyleToggle.setToggleGroup(styleToggleGroup); + classicStyleToggle.setUserData(List.of(Styles.TABS_CLASSIC, "whatever", Styles.TABS_FLOATING)); + classicStyleToggle.getStyleClass().add(Styles.RIGHT_PILL); + + styleToggleGroup.selectedToggleProperty().addListener((obs, old, val) -> { + if (val != null) { + List classes = (List) val.getUserData(); + Styles.addStyleClass(tabs, classes.get(0), classes.get(1), classes.get(2)); + } + }); + + + var styleBox = new HBox(defaultStyleToggle, floatingStyleToggle, classicStyleToggle); + styleBox.setAlignment(Pos.CENTER); // == LAYOUT == @@ -190,7 +215,7 @@ public class TabPanePage extends AbstractPage { ); controls.setAlignment(Pos.CENTER); - var root = new TitledPane("Controller", controls); + var root = new TitledPane("Controller", new VBox(30, controls, styleBox)); root.setCollapsible(false); return root; diff --git a/styles/src/components/_tab-pane.scss b/styles/src/components/_tab-pane.scss index cdd5c46..85d883e 100755 --- a/styles/src/components/_tab-pane.scss +++ b/styles/src/components/_tab-pane.scss @@ -8,7 +8,7 @@ $color-bg: -color-bg-default !default; $color-fg: -color-fg-default !default; $color-border: -color-border-default !default; -// horizontal tabs (tb, top+bottom) +// horizontal tabs (tb = top+bottom) $color-tb-bg-hover: -color-bg-subtle !default; $color-tb-fg-hover: -color-fg-default !default; $color-tb-border-hover: -color-border-default !default; @@ -17,7 +17,7 @@ $color-tb-bg-selected: -color-bg-default !default; $color-tb-fg-selected: -color-fg-default !default; $color-tb-border-selected: -color-accent-emphasis !default; -// vertical tabs (lr, left+right) +// vertical tabs (lr = left+right) $color-lr-bg-hover: -color-bg-subtle !default; $color-lr-fg-hover: -color-fg-default !default; $color-lr-border-hover: -color-border-default !default; @@ -53,7 +53,7 @@ $color-float-bg-selected: -color-bg-default !default; $color-float-border-selected: -color-border-default !default; $tab-float-label-padding-x: 0.6em !default; -$tab-float-label-padding-x-dense: 0.4em !default; +$tab-float-label-padding-x-dense: 0.4em !default; $tab-float-label-padding-y: 0.6em !default; $tab-float-label-padding-y-dense: 0.4em !default; @@ -61,6 +61,13 @@ $header-float-border-width: 1px !default; $tab-float-spacing: 3px !default; $tab-float-width: 150px !default; +// classic tabs +$color-classic-bg: -color-bg-subtle !default; +$color-classic-bg-selected: -color-bg-default !default; +$color-classic-border: -color-border-muted !default; +$header-classic-padding-x: 5px !default; +$header-classic-padding-y: 5px !default; + .tab-pane { >.tab-header-area { @@ -227,7 +234,7 @@ $tab-float-width: 150px !default; } } - // TabPane.STYLE_CLASS_FLOATING + // TabPane.STYLE_CLASS_FLOATING or Styles.TABS_FLOATING &.floating { >.tab-header-area { @@ -287,4 +294,58 @@ $tab-float-width: 150px !default; } } } + + // Styles.TABS_CLASSIC + &.classic { + >.tab-header-area { + -fx-padding: $header-classic-padding-y 0 0 $header-classic-padding-x; + + >.tab-header-background { + -fx-background-insets: 0 0 0 0, 0 0 $header-border-width 0; + -fx-background-color: $color-classic-border, $color-classic-bg; + } + + >.headers-region { + >.tab { + -fx-background-insets: 0; + -fx-background-color: transparent; + + >.tab-container { + -fx-padding: 0; + } + + &:top:selected, + &:bottom:selected { + -fx-background-insets: 0 0 0 0, $header-border-width $header-border-width 0 $header-border-width; + -fx-background-color: $color-classic-border, $color-classic-bg-selected; + } + + &:left:selected, + &:right:selected { + -fx-background-insets: 0 0 0 0, $header-border-width $header-border-width 0 $header-border-width; + -fx-background-color: $color-classic-border, $color-classic-bg-selected; + } + + &:hover, + &:selected { + >.tab-container { + -fx-border-color: none; + } + } + } + } + } + + &:bottom { + >.tab-header-area { + -fx-padding: 0 0 $header-classic-padding-y $header-classic-padding-x; + } + } + + &:right { + >.tab-header-area { + -fx-padding: $header-classic-padding-y $header-classic-padding-x 0 0; + } + } + } }