data_table_theme.dart 11.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// 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';

13 14 15
// Examples can assume:
// late BuildContext context;

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/// 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({
41
    this.decoration,
42
    this.dataRowColor,
43 44 45 46 47 48 49
    @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,
50 51 52 53 54 55 56
    this.dataTextStyle,
    this.headingRowColor,
    this.headingRowHeight,
    this.headingTextStyle,
    this.horizontalMargin,
    this.columnSpacing,
    this.dividerThickness,
57
    this.checkboxHorizontalMargin,
58 59
    this.headingCellCursor,
    this.dataRowCursor,
60 61 62 63 64
  }) : 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;
65

66 67 68
  /// {@macro flutter.material.dataTable.decoration}
  final Decoration? decoration;

69
  /// {@macro flutter.material.dataTable.dataRowColor}
70
  /// {@macro flutter.material.DataTable.dataRowColor}
71
  final MaterialStateProperty<Color?>? dataRowColor;
72 73

  /// {@macro flutter.material.dataTable.dataRowHeight}
74 75 76 77 78 79 80 81 82 83 84
  @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;
85 86

  /// {@macro flutter.material.dataTable.dataTextStyle}
87
  final TextStyle? dataTextStyle;
88 89

  /// {@macro flutter.material.dataTable.headingRowColor}
90
  /// {@macro flutter.material.DataTable.headingRowColor}
91
  final MaterialStateProperty<Color?>? headingRowColor;
92 93

  /// {@macro flutter.material.dataTable.headingRowHeight}
94
  final double? headingRowHeight;
95 96

  /// {@macro flutter.material.dataTable.headingTextStyle}
97
  final TextStyle? headingTextStyle;
98 99

  /// {@macro flutter.material.dataTable.horizontalMargin}
100
  final double? horizontalMargin;
101 102

  /// {@macro flutter.material.dataTable.columnSpacing}
103
  final double? columnSpacing;
104 105

  /// {@macro flutter.material.dataTable.dividerThickness}
106
  final double? dividerThickness;
107

108 109 110
  /// {@macro flutter.material.dataTable.checkboxHorizontalMargin}
  final double? checkboxHorizontalMargin;

111 112 113 114 115 116
  /// 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;

117 118 119
  /// Creates a copy of this object but with the given fields replaced with the
  /// new values.
  DataTableThemeData copyWith({
120
    Decoration? decoration,
121
    MaterialStateProperty<Color?>? dataRowColor,
122 123 124 125
    @Deprecated(
      'Migrate to use dataRowMinHeight and dataRowMaxHeight instead. '
      'This feature was deprecated after v3.7.0-5.0.pre.',
    )
126
    double? dataRowHeight,
127 128
    double? dataRowMinHeight,
    double? dataRowMaxHeight,
129 130 131 132 133 134 135
    TextStyle? dataTextStyle,
    MaterialStateProperty<Color?>? headingRowColor,
    double? headingRowHeight,
    TextStyle? headingTextStyle,
    double? horizontalMargin,
    double? columnSpacing,
    double? dividerThickness,
136
    double? checkboxHorizontalMargin,
137 138
    MaterialStateProperty<MouseCursor?>? headingCellCursor,
    MaterialStateProperty<MouseCursor?>? dataRowCursor,
139 140
  }) {
    return DataTableThemeData(
141
      decoration: decoration ?? this.decoration,
142 143
      dataRowColor: dataRowColor ?? this.dataRowColor,
      dataRowHeight: dataRowHeight ?? this.dataRowHeight,
144 145
      dataRowMinHeight: dataRowMinHeight ?? this.dataRowMinHeight,
      dataRowMaxHeight: dataRowMaxHeight ?? this.dataRowMaxHeight,
146 147 148 149 150 151 152
      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,
153
      checkboxHorizontalMargin: checkboxHorizontalMargin ?? this.checkboxHorizontalMargin,
154 155
      headingCellCursor: headingCellCursor ?? this.headingCellCursor,
      dataRowCursor: dataRowCursor ?? this.dataRowCursor,
156 157 158 159 160 161 162 163 164
    );
  }

  /// Linearly interpolate between two [DataTableThemeData]s.
  ///
  /// The argument `t` must not be null.
  ///
  /// {@macro dart.ui.shadow.lerp}
  static DataTableThemeData lerp(DataTableThemeData a, DataTableThemeData b, double t) {
165 166 167
    if (identical(a, b)) {
      return a;
    }
168
    return DataTableThemeData(
169
      decoration: Decoration.lerp(a.decoration, b.decoration, t),
170
      dataRowColor: MaterialStateProperty.lerp<Color?>(a.dataRowColor, b.dataRowColor, t, Color.lerp),
171 172
      dataRowMinHeight: lerpDouble(a.dataRowMinHeight, b.dataRowMinHeight, t),
      dataRowMaxHeight: lerpDouble(a.dataRowMaxHeight, b.dataRowMaxHeight, t),
173
      dataTextStyle: TextStyle.lerp(a.dataTextStyle, b.dataTextStyle, t),
174
      headingRowColor: MaterialStateProperty.lerp<Color?>(a.headingRowColor, b.headingRowColor, t, Color.lerp),
175 176 177 178
      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),
179
      dividerThickness: lerpDouble(a.dividerThickness, b.dividerThickness, t),
180
      checkboxHorizontalMargin: lerpDouble(a.checkboxHorizontalMargin, b.checkboxHorizontalMargin, t),
181 182
      headingCellCursor: t < 0.5 ? a.headingCellCursor : b.headingCellCursor,
      dataRowCursor: t < 0.5 ? a.dataRowCursor : b.dataRowCursor,
183 184 185 186
    );
  }

  @override
187 188 189
  int get hashCode => Object.hash(
    decoration,
    dataRowColor,
190 191
    dataRowMinHeight,
    dataRowMaxHeight,
192 193 194 195 196 197 198 199
    dataTextStyle,
    headingRowColor,
    headingRowHeight,
    headingTextStyle,
    horizontalMargin,
    columnSpacing,
    dividerThickness,
    checkboxHorizontalMargin,
200 201
    headingCellCursor,
    dataRowCursor,
202
  );
203 204 205

  @override
  bool operator ==(Object other) {
206
    if (identical(this, other)) {
207
      return true;
208 209
    }
    if (other.runtimeType != runtimeType) {
210
      return false;
211
    }
212
    return other is DataTableThemeData
213
      && other.decoration == decoration
214
      && other.dataRowColor == dataRowColor
215 216
      && other.dataRowMinHeight == dataRowMinHeight
      && other.dataRowMaxHeight == dataRowMaxHeight
217 218 219 220 221 222
      && other.dataTextStyle == dataTextStyle
      && other.headingRowColor == headingRowColor
      && other.headingRowHeight == headingRowHeight
      && other.headingTextStyle == headingTextStyle
      && other.horizontalMargin == horizontalMargin
      && other.columnSpacing == columnSpacing
223
      && other.dividerThickness == dividerThickness
224 225 226
      && other.checkboxHorizontalMargin == checkboxHorizontalMargin
      && other.headingCellCursor == headingCellCursor
      && other.dataRowCursor == dataRowCursor;
227 228 229 230 231
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
232
    properties.add(DiagnosticsProperty<Decoration>('decoration', decoration, defaultValue: null));
233
    properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('dataRowColor', dataRowColor, defaultValue: null));
234 235
    properties.add(DoubleProperty('dataRowMinHeight', dataRowMinHeight, defaultValue: null));
    properties.add(DoubleProperty('dataRowMaxHeight', dataRowMaxHeight, defaultValue: null));
236
    properties.add(DiagnosticsProperty<TextStyle>('dataTextStyle', dataTextStyle, defaultValue: null));
237
    properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('headingRowColor', headingRowColor, defaultValue: null));
238 239 240 241 242
    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));
243
    properties.add(DoubleProperty('checkboxHorizontalMargin', checkboxHorizontalMargin, defaultValue: null));
244 245
    properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>?>('headingCellCursor', headingCellCursor, defaultValue: null));
    properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>?>('dataRowCursor', dataRowCursor, defaultValue: null));
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
  }
}

/// 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.
  ///
  /// The [data] must not be null.
  const DataTableTheme({
268
    super.key,
269
    required this.data,
270
    required super.child,
271
  });
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

  /// 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) {
287
    final DataTableTheme? dataTableTheme = context.dependOnInheritedWidgetOfExactType<DataTableTheme>();
288
    return dataTableTheme?.data ?? Theme.of(context).dataTableTheme;
289 290 291 292 293
  }

  @override
  bool updateShouldNotify(DataTableTheme oldWidget) => data != oldWidget.data;
}