From 275272166abc7f57debf7f1854653b41abdfde40 Mon Sep 17 00:00:00 2001 From: Jong Hyun Kim Date: Sun, 17 Nov 2024 15:05:51 +0900 Subject: [PATCH 1/4] Add support for reserved footer area --- CHANGELOG.md | 2 ++ lib/src/controls/navigation/tab_view.dart | 32 +++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3545a08..c6bc18b8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [next] - fix: Add missing properties (`closeIconSize`, `closeButtonStyle`) in `debugFillProperties` and `InfoBarThemeData.merge` ([#1128](https://github.com/bdlukaa/fluent_ui/issues/1128) +- Added `reservedStripWidth` to `TabView` to ensure minimum drag area between tabs and footer, + critical for window manipulation when used in title bar scenarios ([@1106](https://github.com/bdlukaa/fluent_ui/issues/1106)) ## 4.9.2 diff --git a/lib/src/controls/navigation/tab_view.dart b/lib/src/controls/navigation/tab_view.dart index bef5b332c..da07bd29f 100644 --- a/lib/src/controls/navigation/tab_view.dart +++ b/lib/src/controls/navigation/tab_view.dart @@ -73,6 +73,7 @@ class TabView extends StatefulWidget { this.tabWidthBehavior = TabWidthBehavior.equal, this.header, this.footer, + this.reservedStripWidth, this.stripBuilder, this.closeDelayDuration = const Duration(seconds: 1), }); @@ -170,6 +171,18 @@ class TabView extends StatefulWidget { /// Usually a [Text] widget. final Widget? footer; + /// Minimum reserved width at the end of tab strip to ensure space for window controls. + /// This area will be excluded when laying out tabs. + /// + /// When using TabView in a title bar, this space ensures minimum drag area even + /// when many tabs are present. This is critical for window manipulation (dragging, etc) + /// as it guarantees a consistent drag target regardless of tab count. + /// + /// The reserved space is placed after the new tab button (if present) + /// and before the footer (if present). When tabs expand, they will not + /// encroach on this reserved area. + final double? reservedStripWidth; + /// The builder for the strip that contains the tabs. final Widget Function(BuildContext context, Widget strip)? stripBuilder; @@ -244,7 +257,8 @@ class TabView extends StatefulWidget { defaultValue: const Duration(seconds: 1), )) ..add(DoubleProperty('minTabWidth', minTabWidth, defaultValue: 80.0)) - ..add(DoubleProperty('maxTabWidth', maxTabWidth, defaultValue: 240.0)); + ..add(DoubleProperty('maxTabWidth', maxTabWidth, defaultValue: 240.0)) + ..add(DoubleProperty('minFooterWidth', reservedStripWidth)); } } @@ -476,10 +490,11 @@ class _TabViewState extends State { 'You can only create a TabView in a box with defined width', ); - preferredTabWidth = - ((width - (widget.showNewButton ? _kButtonWidth : 0)) / - widget.tabs.length) - .clamp(widget.minTabWidth, widget.maxTabWidth); + preferredTabWidth = ((width - + (widget.showNewButton ? _kButtonWidth : 0) - + (widget.reservedStripWidth ?? 0)) / + widget.tabs.length) + .clamp(widget.minTabWidth, widget.maxTabWidth); final Widget listView = Listener( onPointerSignal: (PointerSignalEvent e) { @@ -583,18 +598,22 @@ class _TabViewState extends State { } final strip = Row(children: [ + // scroll buttons if needed if (showScrollButtons) direction == TextDirection.ltr ? backwardButton() : forwardButton(), + // tabs area (flexible/expanded) if (scrollable) Expanded(child: listView) else Flexible(child: listView), + // scroll buttons if needed if (showScrollButtons) direction == TextDirection.ltr ? forwardButton() : backwardButton(), + // new tab button if (widget.showNewButton) Padding( padding: const EdgeInsetsDirectional.only( @@ -624,6 +643,9 @@ class _TabViewState extends State { localizations.newTabLabel, ), ), + // reserved strip width + if (widget.reservedStripWidth != null) + SizedBox(width: widget.reservedStripWidth), ]); if (widget.stripBuilder != null) { From 993023e60acac833a3f9e2ae9a2e3d2b937592bb Mon Sep 17 00:00:00 2001 From: Jong Hyun Kim Date: Sun, 17 Nov 2024 17:34:37 +0900 Subject: [PATCH 2/4] Add reservedStripWidth example for TabView --- example/lib/screens/navigation/tab_view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/example/lib/screens/navigation/tab_view.dart b/example/lib/screens/navigation/tab_view.dart index 3ac588a52..02b17d123 100644 --- a/example/lib/screens/navigation/tab_view.dart +++ b/example/lib/screens/navigation/tab_view.dart @@ -233,6 +233,7 @@ TabView( height: 400, child: TabView( tabs: tabs!, + reservedStripWidth: 100, currentIndex: currentIndex, onChanged: (index) => setState(() => currentIndex = index), tabWidthBehavior: tabWidthBehavior, From 17df4fea153576abcaefcd5a9d56211a7a0e381d Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:33:32 -0300 Subject: [PATCH 3/4] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6bc18b8e..6500573db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,7 @@ ## [next] - fix: Add missing properties (`closeIconSize`, `closeButtonStyle`) in `debugFillProperties` and `InfoBarThemeData.merge` ([#1128](https://github.com/bdlukaa/fluent_ui/issues/1128) -- Added `reservedStripWidth` to `TabView` to ensure minimum drag area between tabs and footer, - critical for window manipulation when used in title bar scenarios ([@1106](https://github.com/bdlukaa/fluent_ui/issues/1106)) +- feat: Add `TabView.reservedStripWidth`, which adds a minimum empty area between the tabs and the tab view footer ([#1106](https://github.com/bdlukaa/fluent_ui/issues/1106)) ## 4.9.2 From 5626ef7311fb78fdd2bd558acf98beac39a215a9 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:33:49 -0300 Subject: [PATCH 4/4] chore: Update `reservedStripWidth` documentation --- lib/src/controls/navigation/tab_view.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/controls/navigation/tab_view.dart b/lib/src/controls/navigation/tab_view.dart index da07bd29f..a570c25b7 100644 --- a/lib/src/controls/navigation/tab_view.dart +++ b/lib/src/controls/navigation/tab_view.dart @@ -171,16 +171,17 @@ class TabView extends StatefulWidget { /// Usually a [Text] widget. final Widget? footer; - /// Minimum reserved width at the end of tab strip to ensure space for window controls. - /// This area will be excluded when laying out tabs. + /// The minimum width reserved at the end of the tab strip. + /// + /// This reserved space ensures a consistent drag area for window manipulation + /// (e.g., dragging, resizing) even when many tabs are present. This is particularly + /// crucial when `TabView` is used in a title bar. /// /// When using TabView in a title bar, this space ensures minimum drag area even /// when many tabs are present. This is critical for window manipulation (dragging, etc) /// as it guarantees a consistent drag target regardless of tab count. /// - /// The reserved space is placed after the new tab button (if present) - /// and before the footer (if present). When tabs expand, they will not - /// encroach on this reserved area. + /// If `null`, no reserved width is enforced. final double? reservedStripWidth; /// The builder for the strip that contains the tabs.