diff --git a/lib/src/widgets/window_caption_button.dart b/lib/src/widgets/window_caption_button.dart index fb20db7..1512b7f 100644 --- a/lib/src/widgets/window_caption_button.dart +++ b/lib/src/widgets/window_caption_button.dart @@ -277,6 +277,8 @@ class WindowCaptionButton extends StatefulWidget { super.key, this.brightness, this.icon, + this.hovered = false, + this.pressed = false, this.iconName, required this.onPressed, }); @@ -285,6 +287,8 @@ class WindowCaptionButton extends StatefulWidget { super.key, this.brightness, this.icon, + this.hovered = false, + this.pressed = false, this.onPressed, }) : iconName = _kIconChromeMinimize; @@ -292,6 +296,8 @@ class WindowCaptionButton extends StatefulWidget { super.key, this.brightness, this.icon, + this.hovered = false, + this.pressed = false, this.onPressed, }) : iconName = _kIconChromeMaximize; @@ -299,6 +305,8 @@ class WindowCaptionButton extends StatefulWidget { super.key, this.brightness, this.icon, + this.hovered = false, + this.pressed = false, this.onPressed, }) : iconName = _kIconChromeUnmaximize; @@ -306,6 +314,8 @@ class WindowCaptionButton extends StatefulWidget { super.key, this.brightness, this.icon, + this.hovered = false, + this.pressed = false, this.onPressed, }) : iconName = _kIconChromeClose, _lightButtonBgColorScheme = _ButtonBgColorScheme( @@ -336,6 +346,16 @@ class WindowCaptionButton extends StatefulWidget { final String? iconName; final VoidCallback? onPressed; + /// Shows the hovered look even when Flutter does not see the pointer. + /// + /// For input the platform handles over the button, such as a Windows 11 + /// maximize button that reports `HTMAXBUTTON` to open Snap Layouts. + final bool hovered; + + /// Shows the pressed look even when Flutter does not see the pointer. + /// See [hovered]. + final bool pressed; + _ButtonBgColorScheme _lightButtonBgColorScheme = _ButtonBgColorScheme( normal: Colors.transparent, hovered: Colors.black.withValues(alpha: 0.0373), @@ -389,11 +409,11 @@ class _WindowCaptionButtonState extends State { Color bgColor = widget.buttonBgColorScheme.normal; Color iconColor = widget.buttonIconColorScheme.normal; - if (_isHovering) { + if (_isHovering || widget.hovered) { bgColor = widget.buttonBgColorScheme.hovered; iconColor = widget.buttonIconColorScheme.hovered; } - if (_isPressed) { + if (_isPressed || widget.pressed) { bgColor = widget.buttonBgColorScheme.pressed; iconColor = widget.buttonIconColorScheme.pressed; } diff --git a/test/window_caption_button_test.dart b/test/window_caption_button_test.dart new file mode 100644 index 0000000..1c8f664 --- /dev/null +++ b/test/window_caption_button_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:window_manager/window_manager.dart'; + +Color? _background(WidgetTester tester) { + final container = tester.widget( + find.descendant( + of: find.byType(WindowCaptionButton), + matching: find.byType(Container), + ), + ); + return (container.decoration as BoxDecoration?)?.color; +} + +Future _pump(WidgetTester tester, WindowCaptionButton button) { + return tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center(child: button), + ), + ); +} + +void main() { + testWidgets('idle button has the normal background', (tester) async { + await _pump(tester, WindowCaptionButton.maximize(onPressed: () {})); + expect(_background(tester), Colors.transparent); + }); + + testWidgets('hovered shows the hover look without a pointer', (tester) async { + await _pump( + tester, + WindowCaptionButton.maximize(onPressed: () {}, hovered: true), + ); + expect(_background(tester), Colors.black.withValues(alpha: 0.0373)); + }); + + testWidgets('pressed wins over hovered', (tester) async { + await _pump( + tester, + WindowCaptionButton.unmaximize( + onPressed: () {}, + hovered: true, + pressed: true, + ), + ); + expect(_background(tester), Colors.black.withValues(alpha: 0.0241)); + }); + + testWidgets('dark close button uses its own hover color', (tester) async { + await _pump( + tester, + WindowCaptionButton.close( + brightness: Brightness.dark, + onPressed: () {}, + hovered: true, + ), + ); + expect(_background(tester), const Color(0xffC42B1C)); + }); +}