diff --git a/CHANGELOG.md b/CHANGELOG.md index 2717b638..27af9c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.2] +* Added support for using an icon inside a push button + ## [2.1.1] * Fixed a bug where `MacosPulldownMenuItem` would not show an alert dialog when tapped. diff --git a/example/lib/pages/buttons_page.dart b/example/lib/pages/buttons_page.dart index 26952d90..de8e4292 100644 --- a/example/lib/pages/buttons_page.dart +++ b/example/lib/pages/buttons_page.dart @@ -247,6 +247,196 @@ class _ButtonsPageState extends State { ], ), const SizedBox(height: 16), + Text( + 'Primary with Icon', + style: MacosTypography + .of(context) + .title2, + ), + Row( + children: [ + PushButton( + controlSize: ControlSize.mini, + iconData: CupertinoIcons.star, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Mini'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.small, + iconData: CupertinoIcons.plus_rectangle, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Small'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.regular, + iconData: CupertinoIcons.minus_rectangle, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Regular'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.large, + iconData: CupertinoIcons.eye, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Large'), + ) + ], + ), + const SizedBox(height: 16), Text( 'Secondary', style: MacosTypography.of(context).title2, @@ -431,6 +621,200 @@ class _ButtonsPageState extends State { ], ), const SizedBox(height: 16), + Text( + 'Secondary with Icon', + style: MacosTypography + .of(context) + .title2, + ), + Row( + children: [ + PushButton( + controlSize: ControlSize.mini, + iconData: CupertinoIcons.star, + secondary: true, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Mini'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.small, + iconData: CupertinoIcons.plus_rectangle, + secondary: true, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Small'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.regular, + iconData: CupertinoIcons.minus_rectangle, + secondary: true, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Regular'), + ), + const SizedBox(width: 8), + PushButton( + controlSize: ControlSize.large, + iconData: CupertinoIcons.eye, + secondary: true, + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) { + return MacosScaffold( + toolBar: const ToolBar( + title: Text('New page'), + ), + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: PushButton( + controlSize: ControlSize.regular, + child: const Text('Go Back'), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + ); + }, + ), + ResizablePane( + minSize: 180, + startSize: 200, + windowBreakpoint: 700, + resizableSide: ResizableSide.left, + builder: (_, __) { + return const Center( + child: Text('Resizable Pane'), + ); + }, + ), + ], + ); + }, + ), + ); + }, + child: const Text('Large'), + ) + ], + ), + const SizedBox(height: 16), const WidgetTextTitle1(widgetName: 'HelpButton'), Divider(color: MacosTheme.of(context).dividerColor), HelpButton(onPressed: () {}), diff --git a/lib/src/buttons/push_button.dart b/lib/src/buttons/push_button.dart index e95a9857..bc732011 100644 --- a/lib/src/buttons/push_button.dart +++ b/lib/src/buttons/push_button.dart @@ -77,6 +77,34 @@ extension PushButtonControlSizeX on ControlSize { } } + /// Determines the button's icon size + double get iconSize { + switch (this) { + case ControlSize.mini: + return 8; + case ControlSize.small: + return 12; + case ControlSize.regular: + return 16; + case ControlSize.large: + return 20; + } + } + + /// Determines the button's left icon padding + EdgeInsets get iconPadding { + switch (this) { + case ControlSize.mini: + return const EdgeInsets.fromLTRB(5, 0, 0, 0); + case ControlSize.small: + return const EdgeInsets.fromLTRB(7, 0, 0, 0); + case ControlSize.regular: + return const EdgeInsets.fromLTRB(10, 0, 0, 0); + case ControlSize.large: + return const EdgeInsets.fromLTRB(12, 0, 0, 0); + } + } + /// Determines the button's minimum size. BoxConstraints get constraints { switch (this) { @@ -130,6 +158,7 @@ class PushButton extends StatefulWidget { this.semanticLabel, this.mouseCursor = SystemMouseCursors.basic, this.secondary, + this.iconData, }) : assert(pressedOpacity == null || (pressedOpacity >= 0.0 && pressedOpacity <= 1.0)); @@ -202,6 +231,10 @@ class PushButton extends StatefulWidget { /// Can still be overridden if the [color] attribute is non-null. final bool? secondary; + /// An optional iconData that can be added to a button. + /// This is an iconData instead of icon so we can control the size + final IconData? iconData; + /// Whether the button is enabled or disabled. Buttons are disabled by default. To /// enable a button, set its [onPressed] property to a non-null value. bool get enabled => onPressed != null; @@ -221,6 +254,7 @@ class PushButton extends StatefulWidget { ifFalse: 'disabled', )); properties.add(DiagnosticsProperty('secondary', secondary)); + properties.add(DiagnosticsProperty('iconData', iconData)); } @override @@ -361,18 +395,31 @@ class PushButtonState extends State foregroundDecoration: buttonHeldDown ? _getClickEffectBoxDecoration() : const BoxDecoration(), - child: Padding( - padding: widget.controlSize.padding, - child: Align( - alignment: widget.alignment, - widthFactor: 1.0, - heightFactor: 1.0, - child: DefaultTextStyle( - style: widget.controlSize.textStyle(baseStyle), - child: widget.child, + child: Row( + children: [ + widget.iconData != null + ? Padding(padding: widget.controlSize.iconPadding,) + : const SizedBox.shrink(), + widget.iconData != null ? Icon(widget.iconData, + size: widget.controlSize.iconSize, + color: Colors.white) : const SizedBox.shrink(), + Padding( + padding: widget.controlSize.padding, + child: Align( + alignment: widget.alignment, + widthFactor: 1.0, + heightFactor: 1.0, + child: Row(children: [ + DefaultTextStyle( + style: widget.controlSize.textStyle( + baseStyle), + child: widget.child, + ), + ],) + ), ), - ), - ), + ], + ) ), ); }, diff --git a/pubspec.yaml b/pubspec.yaml index 65235877..bc9d3bcb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: macos_ui description: Flutter widgets and themes implementing the current macOS design language. -version: 2.1.1 +version: 2.1.2 homepage: "https://macosui.dev" repository: "https://github.com/GroovinChip/macos_ui" diff --git a/test/buttons/push_button_test.dart b/test/buttons/push_button_test.dart index 981c21df..4142ffac 100644 --- a/test/buttons/push_button_test.dart +++ b/test/buttons/push_button_test.dart @@ -104,6 +104,7 @@ void main() { 'borderRadius: BorderRadius.circular(4.0)', 'disabled', 'secondary: null', + 'iconData: null', ], ); });