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 | |
5 | import 'basic.dart'; |
6 | import 'framework.dart'; |
7 | |
8 | class _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. |
56 | class 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 | |