1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'basic.dart';
6import 'framework.dart';
7
8class _GridPaperPainter extends CustomPainter {
9 const _GridPaperPainter({
10 required this.color,
11 required this.interval,
12 required this.divisions,
13 required this.subdivisions,
14 });
15
16 final Color color;
17 final double interval;
18 final int divisions;
19 final int subdivisions;
20
21 @override
22 void paint(Canvas canvas, Size size) {
23 final Paint linePaint = Paint()
24 ..color = color;
25 final double allDivisions = (divisions * subdivisions).toDouble();
26 for (double x = 0.0; x <= size.width; x += interval / allDivisions) {
27 linePaint.strokeWidth = (x % interval == 0.0) ? 1.0 : (x % (interval / subdivisions) == 0.0) ? 0.5 : 0.25;
28 canvas.drawLine(Offset(x, 0.0), Offset(x, size.height), linePaint);
29 }
30 for (double y = 0.0; y <= size.height; y += interval / allDivisions) {
31 linePaint.strokeWidth = (y % interval == 0.0) ? 1.0 : (y % (interval / subdivisions) == 0.0) ? 0.5 : 0.25;
32 canvas.drawLine(Offset(0.0, y), Offset(size.width, y), linePaint);
33 }
34 }
35
36 @override
37 bool shouldRepaint(_GridPaperPainter oldPainter) {
38 return oldPainter.color != color
39 || oldPainter.interval != interval
40 || oldPainter.divisions != divisions
41 || oldPainter.subdivisions != subdivisions;
42 }
43
44 @override
45 bool hitTest(Offset position) => false;
46}
47
48/// A widget that draws a rectilinear grid of lines one pixel wide.
49///
50/// Useful with a [Stack] for visualizing your layout along a grid.
51///
52/// The grid's origin (where the first primary horizontal line and the first
53/// primary vertical line intersect) is at the top left of the widget.
54///
55/// The grid is drawn over the [child] widget.
56class GridPaper extends StatelessWidget {
57 /// Creates a widget that draws a rectilinear grid of 1-pixel-wide lines.
58 const GridPaper({
59 super.key,
60 this.color = const Color(0x7FC3E8F3),
61 this.interval = 100.0,
62 this.divisions = 2,
63 this.subdivisions = 5,
64 this.child,
65 }) : assert(divisions > 0, 'The "divisions" property must be greater than zero. If there were no divisions, the grid paper would not paint anything.'),
66 assert(subdivisions > 0, 'The "subdivisions" property must be greater than zero. If there were no subdivisions, the grid paper would not paint anything.');
67
68 /// The color to draw the lines in the grid.
69 ///
70 /// Defaults to a light blue commonly seen on traditional grid paper.
71 final Color color;
72
73 /// The distance between the primary lines in the grid, in logical pixels.
74 ///
75 /// Each primary line is one logical pixel wide.
76 final double interval;
77
78 /// The number of major divisions within each primary grid cell.
79 ///
80 /// This is the number of major divisions per [interval], including the
81 /// primary grid's line.
82 ///
83 /// The lines after the first are half a logical pixel wide.
84 ///
85 /// If this is set to 2 (the default), then for each [interval] there will be
86 /// a 1-pixel line on the left, a half-pixel line in the middle, and a 1-pixel
87 /// line on the right (the latter being the 1-pixel line on the left of the
88 /// next [interval]).
89 final int divisions;
90
91 /// The number of minor divisions within each major division, including the
92 /// major division itself.
93 ///
94 /// If [subdivisions] is 5 (the default), it means that there will be four
95 /// lines between each major ([divisions]) line.
96 ///
97 /// The subdivision lines after the first are a quarter of a logical pixel wide.
98 final int subdivisions;
99
100 /// The widget below this widget in the tree.
101 ///
102 /// {@macro flutter.widgets.ProxyWidget.child}
103 final Widget? child;
104
105 @override
106 Widget build(BuildContext context) {
107 return CustomPaint(
108 foregroundPainter: _GridPaperPainter(
109 color: color,
110 interval: interval,
111 divisions: divisions,
112 subdivisions: subdivisions,
113 ),
114 child: child,
115 );
116 }
117}
118