Skip to content

Commit d1d56fe

Browse files
committed
Reimplement the rotating cube in the demo app
1 parent 77c9e39 commit d1d56fe

File tree

1 file changed

+147
-34
lines changed

1 file changed

+147
-34
lines changed

examples/multi_window_ref_app/lib/app/regular_window_content.dart

Lines changed: 147 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
22
import 'package:multi_window_ref_app/app/window_controller_render.dart';
33
import 'package:multi_window_ref_app/app/window_manager_model.dart';
44
import 'package:multi_window_ref_app/app/window_settings.dart';
5+
import 'dart:math';
6+
import 'package:vector_math/vector_math_64.dart';
57

6-
class RegularWindowContent extends StatelessWidget {
8+
class RegularWindowContent extends StatefulWidget {
79
const RegularWindowContent(
810
{super.key,
911
required this.window,
@@ -14,54 +16,111 @@ class RegularWindowContent extends StatelessWidget {
1416
final WindowSettings windowSettings;
1517
final WindowManagerModel windowManagerModel;
1618

19+
@override
20+
State<StatefulWidget> createState() => _RegularWindowContentState();
21+
}
22+
23+
class _RegularWindowContentState extends State<RegularWindowContent>
24+
with SingleTickerProviderStateMixin {
25+
late final AnimationController _animation;
26+
late final Color cubeColor;
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
_animation = AnimationController(
32+
vsync: this,
33+
lowerBound: 0,
34+
upperBound: 2 * pi,
35+
duration: const Duration(seconds: 15),
36+
)..repeat();
37+
cubeColor = _generateRandomDarkColor();
38+
}
39+
40+
@override
41+
void dispose() {
42+
_animation.dispose();
43+
super.dispose();
44+
}
45+
46+
Color _generateRandomDarkColor() {
47+
final random = Random();
48+
const int lowerBound = 32;
49+
const int span = 160;
50+
int red = lowerBound + random.nextInt(span);
51+
int green = lowerBound + random.nextInt(span);
52+
int blue = lowerBound + random.nextInt(span);
53+
return Color.fromARGB(255, red, green, blue);
54+
}
55+
1756
@override
1857
Widget build(BuildContext context) {
1958
final child = Scaffold(
20-
appBar: AppBar(title: Text('${window.type}')),
59+
appBar: AppBar(title: Text('${widget.window.type}')),
2160
body: Center(
22-
child: Column(
23-
mainAxisAlignment: MainAxisAlignment.center,
24-
crossAxisAlignment: CrossAxisAlignment.center,
25-
children: [
26-
ElevatedButton(
27-
onPressed: () {
28-
windowManagerModel.add(KeyedWindowController(
29-
controller: RegularWindowController()));
30-
},
31-
child: const Text('Create Regular Window'),
32-
),
33-
const SizedBox(height: 20),
34-
ListenableBuilder(
35-
listenable: window,
36-
builder: (BuildContext context, Widget? _) {
37-
return Text(
38-
'View #${window.view?.viewId ?? "Unknown"}\n'
39-
'Parent View: ${window.parentViewId}\n'
40-
'Logical Size: ${window.size?.width ?? "?"}\u00D7${window.size?.height ?? "?"}\n'
41-
'DPR: ${MediaQuery.of(context).devicePixelRatio}',
42-
textAlign: TextAlign.center,
61+
child: Row(
62+
mainAxisAlignment: MainAxisAlignment.center,
63+
children: [
64+
Column(
65+
mainAxisAlignment: MainAxisAlignment.center,
66+
children: [
67+
AnimatedBuilder(
68+
animation: _animation,
69+
builder: (context, child) {
70+
return CustomPaint(
71+
size: const Size(200, 200),
72+
painter: _RotatedWireCube(
73+
angle: _animation.value, color: cubeColor),
4374
);
44-
})
45-
],
46-
),
47-
),
75+
},
76+
),
77+
],
78+
),
79+
Column(
80+
mainAxisAlignment: MainAxisAlignment.center,
81+
crossAxisAlignment: CrossAxisAlignment.center,
82+
children: [
83+
ElevatedButton(
84+
onPressed: () {
85+
widget.windowManagerModel.add(KeyedWindowController(
86+
controller: RegularWindowController()));
87+
},
88+
child: const Text('Create Regular Window'),
89+
),
90+
const SizedBox(height: 20),
91+
ListenableBuilder(
92+
listenable: widget.window,
93+
builder: (BuildContext context, Widget? _) {
94+
return Text(
95+
'View #${widget.window.view?.viewId ?? "Unknown"}\n'
96+
'Parent View: ${widget.window.parentViewId}\n'
97+
'Logical Size: ${widget.window.size?.width ?? "?"}\u00D7${widget.window.size?.height ?? "?"}\n'
98+
'DPR: ${MediaQuery.of(context).devicePixelRatio}',
99+
textAlign: TextAlign.center,
100+
);
101+
})
102+
],
103+
),
104+
],
105+
)),
48106
);
49107

50108
return ViewAnchor(
51109
view: ListenableBuilder(
52-
listenable: windowManagerModel,
110+
listenable: widget.windowManagerModel,
53111
builder: (BuildContext context, Widget? _) {
54112
final List<Widget> childViews = <Widget>[];
55113
for (final KeyedWindowController controller
56-
in windowManagerModel.windows) {
57-
if (controller.parent == window) {
114+
in widget.windowManagerModel.windows) {
115+
if (controller.parent == widget.window) {
58116
childViews.add(WindowControllerRender(
59117
controller: controller.controller,
60118
key: controller.key,
61-
windowSettings: windowSettings,
62-
windowManagerModel: windowManagerModel,
63-
onDestroyed: () => windowManagerModel.remove(controller),
64-
onError: () => windowManagerModel.remove(controller),
119+
windowSettings: widget.windowSettings,
120+
windowManagerModel: widget.windowManagerModel,
121+
onDestroyed: () =>
122+
widget.windowManagerModel.remove(controller),
123+
onError: () => widget.windowManagerModel.remove(controller),
65124
));
66125
}
67126
}
@@ -71,3 +130,57 @@ class RegularWindowContent extends StatelessWidget {
71130
child: child);
72131
}
73132
}
133+
134+
class _RotatedWireCube extends CustomPainter {
135+
static List<Vector3> vertices = [
136+
Vector3(-0.5, -0.5, -0.5),
137+
Vector3(0.5, -0.5, -0.5),
138+
Vector3(0.5, 0.5, -0.5),
139+
Vector3(-0.5, 0.5, -0.5),
140+
Vector3(-0.5, -0.5, 0.5),
141+
Vector3(0.5, -0.5, 0.5),
142+
Vector3(0.5, 0.5, 0.5),
143+
Vector3(-0.5, 0.5, 0.5),
144+
];
145+
146+
static const List<List<int>> edges = [
147+
[0, 1], [1, 2], [2, 3], [3, 0], // Front face
148+
[4, 5], [5, 6], [6, 7], [7, 4], // Back face
149+
[0, 4], [1, 5], [2, 6], [3, 7], // Connecting front and back
150+
];
151+
152+
final double angle;
153+
final Color color;
154+
155+
_RotatedWireCube({required this.angle, required this.color});
156+
157+
Offset scaleAndCenter(Vector3 point, double size, Offset center) {
158+
final scale = size / 2;
159+
return Offset(center.dx + point.x * scale, center.dy - point.y * scale);
160+
}
161+
162+
@override
163+
void paint(Canvas canvas, Size size) {
164+
final rotatedVertices = vertices
165+
.map((vertex) => Matrix4.rotationX(angle).transformed3(vertex))
166+
.map((vertex) => Matrix4.rotationY(angle).transformed3(vertex))
167+
.map((vertex) => Matrix4.rotationZ(angle).transformed3(vertex))
168+
.toList();
169+
170+
final center = Offset(size.width / 2, size.height / 2);
171+
172+
final paint = Paint()
173+
..color = color
174+
..style = PaintingStyle.stroke
175+
..strokeWidth = 2;
176+
177+
for (var edge in edges) {
178+
final p1 = scaleAndCenter(rotatedVertices[edge[0]], size.width, center);
179+
final p2 = scaleAndCenter(rotatedVertices[edge[1]], size.width, center);
180+
canvas.drawLine(p1, p2, paint);
181+
}
182+
}
183+
184+
@override
185+
bool shouldRepaint(_RotatedWireCube oldDelegate) => true;
186+
}

0 commit comments

Comments
 (0)