// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'material_state.dart'; import 'theme.dart'; // Examples can assume: // late BuildContext context; /// Defines default property values for descendant [DataTable] /// widgets. /// /// Descendant widgets obtain the current [DataTableThemeData] object /// using `DataTableTheme.of(context)`. Instances of /// [DataTableThemeData] can be customized with /// [DataTableThemeData.copyWith]. /// /// Typically a [DataTableThemeData] is specified as part of the /// overall [Theme] with [ThemeData.dataTableTheme]. /// /// All [DataTableThemeData] properties are `null` by default. When /// null, the [DataTable] will use the values from [ThemeData] if they exist, /// otherwise it will provide its own defaults based on the overall [Theme]'s /// textTheme and colorScheme. See the individual [DataTable] properties for /// details. /// /// See also: /// /// * [ThemeData], which describes the overall theme information for the /// application. @immutable class DataTableThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.dataTableTheme]. const DataTableThemeData({ this.decoration, this.dataRowColor, @Deprecated( 'Migrate to use dataRowMinHeight and dataRowMaxHeight instead. ' 'This feature was deprecated after v3.7.0-5.0.pre.', ) double? dataRowHeight, double? dataRowMinHeight, double? dataRowMaxHeight, this.dataTextStyle, this.headingRowColor, this.headingRowHeight, this.headingTextStyle, this.horizontalMargin, this.columnSpacing, this.dividerThickness, this.checkboxHorizontalMargin, this.headingCellCursor, this.dataRowCursor, }) : assert(dataRowMinHeight == null || dataRowMaxHeight == null || dataRowMaxHeight >= dataRowMinHeight), assert(dataRowHeight == null || (dataRowMinHeight == null && dataRowMaxHeight == null), 'dataRowHeight ($dataRowHeight) must not be set if dataRowMinHeight ($dataRowMinHeight) or dataRowMaxHeight ($dataRowMaxHeight) are set.'), dataRowMinHeight = dataRowHeight ?? dataRowMinHeight, dataRowMaxHeight = dataRowHeight ?? dataRowMaxHeight; /// {@macro flutter.material.dataTable.decoration} final Decoration? decoration; /// {@macro flutter.material.dataTable.dataRowColor} /// {@macro flutter.material.DataTable.dataRowColor} final MaterialStateProperty<Color?>? dataRowColor; /// {@macro flutter.material.dataTable.dataRowHeight} @Deprecated( 'Migrate to use dataRowMinHeight and dataRowMaxHeight instead. ' 'This feature was deprecated after v3.7.0-5.0.pre.', ) double? get dataRowHeight => dataRowMinHeight == dataRowMaxHeight ? dataRowMinHeight : null; /// {@macro flutter.material.dataTable.dataRowMinHeight} final double? dataRowMinHeight; /// {@macro flutter.material.dataTable.dataRowMaxHeight} final double? dataRowMaxHeight; /// {@macro flutter.material.dataTable.dataTextStyle} final TextStyle? dataTextStyle; /// {@macro flutter.material.dataTable.headingRowColor} /// {@macro flutter.material.DataTable.headingRowColor} final MaterialStateProperty<Color?>? headingRowColor; /// {@macro flutter.material.dataTable.headingRowHeight} final double? headingRowHeight; /// {@macro flutter.material.dataTable.headingTextStyle} final TextStyle? headingTextStyle; /// {@macro flutter.material.dataTable.horizontalMargin} final double? horizontalMargin; /// {@macro flutter.material.dataTable.columnSpacing} final double? columnSpacing; /// {@macro flutter.material.dataTable.dividerThickness} final double? dividerThickness; /// {@macro flutter.material.dataTable.checkboxHorizontalMargin} final double? checkboxHorizontalMargin; /// If specified, overrides the default value of [DataColumn.mouseCursor]. final MaterialStateProperty<MouseCursor?>? headingCellCursor; /// If specified, overrides the default value of [DataRow.mouseCursor]. final MaterialStateProperty<MouseCursor?>? dataRowCursor; /// Creates a copy of this object but with the given fields replaced with the /// new values. DataTableThemeData copyWith({ Decoration? decoration, MaterialStateProperty<Color?>? dataRowColor, @Deprecated( 'Migrate to use dataRowMinHeight and dataRowMaxHeight instead. ' 'This feature was deprecated after v3.7.0-5.0.pre.', ) double? dataRowHeight, double? dataRowMinHeight, double? dataRowMaxHeight, TextStyle? dataTextStyle, MaterialStateProperty<Color?>? headingRowColor, double? headingRowHeight, TextStyle? headingTextStyle, double? horizontalMargin, double? columnSpacing, double? dividerThickness, double? checkboxHorizontalMargin, MaterialStateProperty<MouseCursor?>? headingCellCursor, MaterialStateProperty<MouseCursor?>? dataRowCursor, }) { assert(dataRowHeight == null || (dataRowMinHeight == null && dataRowMaxHeight == null), 'dataRowHeight ($dataRowHeight) must not be set if dataRowMinHeight ($dataRowMinHeight) or dataRowMaxHeight ($dataRowMaxHeight) are set.'); dataRowMinHeight = dataRowHeight ?? dataRowMinHeight; dataRowMaxHeight = dataRowHeight ?? dataRowMaxHeight; return DataTableThemeData( decoration: decoration ?? this.decoration, dataRowColor: dataRowColor ?? this.dataRowColor, dataRowMinHeight: dataRowMinHeight ?? this.dataRowMinHeight, dataRowMaxHeight: dataRowMaxHeight ?? this.dataRowMaxHeight, dataTextStyle: dataTextStyle ?? this.dataTextStyle, headingRowColor: headingRowColor ?? this.headingRowColor, headingRowHeight: headingRowHeight ?? this.headingRowHeight, headingTextStyle: headingTextStyle ?? this.headingTextStyle, horizontalMargin: horizontalMargin ?? this.horizontalMargin, columnSpacing: columnSpacing ?? this.columnSpacing, dividerThickness: dividerThickness ?? this.dividerThickness, checkboxHorizontalMargin: checkboxHorizontalMargin ?? this.checkboxHorizontalMargin, headingCellCursor: headingCellCursor ?? this.headingCellCursor, dataRowCursor: dataRowCursor ?? this.dataRowCursor, ); } /// Linearly interpolate between two [DataTableThemeData]s. /// /// {@macro dart.ui.shadow.lerp} static DataTableThemeData lerp(DataTableThemeData a, DataTableThemeData b, double t) { if (identical(a, b)) { return a; } return DataTableThemeData( decoration: Decoration.lerp(a.decoration, b.decoration, t), dataRowColor: MaterialStateProperty.lerp<Color?>(a.dataRowColor, b.dataRowColor, t, Color.lerp), dataRowMinHeight: lerpDouble(a.dataRowMinHeight, b.dataRowMinHeight, t), dataRowMaxHeight: lerpDouble(a.dataRowMaxHeight, b.dataRowMaxHeight, t), dataTextStyle: TextStyle.lerp(a.dataTextStyle, b.dataTextStyle, t), headingRowColor: MaterialStateProperty.lerp<Color?>(a.headingRowColor, b.headingRowColor, t, Color.lerp), headingRowHeight: lerpDouble(a.headingRowHeight, b.headingRowHeight, t), headingTextStyle: TextStyle.lerp(a.headingTextStyle, b.headingTextStyle, t), horizontalMargin: lerpDouble(a.horizontalMargin, b.horizontalMargin, t), columnSpacing: lerpDouble(a.columnSpacing, b.columnSpacing, t), dividerThickness: lerpDouble(a.dividerThickness, b.dividerThickness, t), checkboxHorizontalMargin: lerpDouble(a.checkboxHorizontalMargin, b.checkboxHorizontalMargin, t), headingCellCursor: t < 0.5 ? a.headingCellCursor : b.headingCellCursor, dataRowCursor: t < 0.5 ? a.dataRowCursor : b.dataRowCursor, ); } @override int get hashCode => Object.hash( decoration, dataRowColor, dataRowMinHeight, dataRowMaxHeight, dataTextStyle, headingRowColor, headingRowHeight, headingTextStyle, horizontalMargin, columnSpacing, dividerThickness, checkboxHorizontalMargin, headingCellCursor, dataRowCursor, ); @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is DataTableThemeData && other.decoration == decoration && other.dataRowColor == dataRowColor && other.dataRowMinHeight == dataRowMinHeight && other.dataRowMaxHeight == dataRowMaxHeight && other.dataTextStyle == dataTextStyle && other.headingRowColor == headingRowColor && other.headingRowHeight == headingRowHeight && other.headingTextStyle == headingTextStyle && other.horizontalMargin == horizontalMargin && other.columnSpacing == columnSpacing && other.dividerThickness == dividerThickness && other.checkboxHorizontalMargin == checkboxHorizontalMargin && other.headingCellCursor == headingCellCursor && other.dataRowCursor == dataRowCursor; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<Decoration>('decoration', decoration, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('dataRowColor', dataRowColor, defaultValue: null)); properties.add(DoubleProperty('dataRowMinHeight', dataRowMinHeight, defaultValue: null)); properties.add(DoubleProperty('dataRowMaxHeight', dataRowMaxHeight, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('dataTextStyle', dataTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('headingRowColor', headingRowColor, defaultValue: null)); properties.add(DoubleProperty('headingRowHeight', headingRowHeight, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('headingTextStyle', headingTextStyle, defaultValue: null)); properties.add(DoubleProperty('horizontalMargin', horizontalMargin, defaultValue: null)); properties.add(DoubleProperty('columnSpacing', columnSpacing, defaultValue: null)); properties.add(DoubleProperty('dividerThickness', dividerThickness, defaultValue: null)); properties.add(DoubleProperty('checkboxHorizontalMargin', checkboxHorizontalMargin, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>?>('headingCellCursor', headingCellCursor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>?>('dataRowCursor', dataRowCursor, defaultValue: null)); } } /// Applies a data table theme to descendant [DataTable] widgets. /// /// Descendant widgets obtain the current theme's [DataTableTheme] object using /// [DataTableTheme.of]. When a widget uses [DataTableTheme.of], it is /// automatically rebuilt if the theme later changes. /// /// A data table theme can be specified as part of the overall Material /// theme using [ThemeData.dataTableTheme]. /// /// See also: /// /// * [DataTableThemeData], which describes the actual configuration /// of a data table theme. class DataTableTheme extends InheritedWidget { /// Constructs a data table theme that configures all descendant /// [DataTable] widgets. const DataTableTheme({ super.key, required this.data, required super.child, }); /// The properties used for all descendant [DataTable] widgets. final DataTableThemeData data; /// Returns the configuration [data] from the closest /// [DataTableTheme] ancestor. If there is no ancestor, it returns /// [ThemeData.dataTableTheme]. Applications can assume that the /// returned value will not be null. /// /// Typical usage is as follows: /// /// ```dart /// DataTableThemeData theme = DataTableTheme.of(context); /// ``` static DataTableThemeData of(BuildContext context) { final DataTableTheme? dataTableTheme = context.dependOnInheritedWidgetOfExactType<DataTableTheme>(); return dataTableTheme?.data ?? Theme.of(context).dataTableTheme; } @override bool updateShouldNotify(DataTableTheme oldWidget) => data != oldWidget.data; }