Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(686)

Side by Side Diff: sky/sdk/lib/widgets/popup_menu.dart

Issue 1234063003: Remove PopupMenuController (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: rebase Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/example/stocks/lib/stock_menu.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:async';
6 import 'dart:math' as math; 5 import 'dart:math' as math;
7 import 'dart:sky' as sky; 6 import 'dart:sky' as sky;
8 7
9 import 'package:sky/animation/animation_performance.dart'; 8 import 'package:sky/animation/animation_performance.dart';
10 import 'package:sky/painting/box_painter.dart'; 9 import 'package:sky/painting/box_painter.dart';
11 import 'package:sky/theme/colors.dart'; 10 import 'package:sky/theme/colors.dart';
12 import 'package:sky/theme/shadows.dart'; 11 import 'package:sky/theme/shadows.dart';
13 import 'package:sky/widgets/animated_component.dart'; 12 import 'package:sky/widgets/animated_component.dart';
14 import 'package:sky/widgets/basic.dart'; 13 import 'package:sky/widgets/basic.dart';
15 import 'package:sky/widgets/popup_menu_item.dart'; 14 import 'package:sky/widgets/popup_menu_item.dart';
16 import 'package:sky/widgets/scrollable_viewport.dart'; 15 import 'package:sky/widgets/scrollable_viewport.dart';
17 16
18 const Duration _kMenuOpenDuration = const Duration(milliseconds: 300); 17 const Duration _kMenuOpenDuration = const Duration(milliseconds: 300);
19 const Duration _kMenuCloseDuration = const Duration(milliseconds: 200); 18 const Duration _kMenuCloseDuration = const Duration(milliseconds: 200);
20 const Duration _kMenuCloseDelay = const Duration(milliseconds: 100); 19 const Duration _kMenuCloseDelay = const Duration(milliseconds: 100);
21 const double _kMenuWidthStep = 56.0; 20 const double _kMenuWidthStep = 56.0;
22 const double _kMenuMargin = 16.0; // 24.0 on tablet 21 const double _kMenuMargin = 16.0; // 24.0 on tablet
23 const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; 22 const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
24 const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; 23 const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
25 const double _kMenuHorizontalPadding = 16.0; 24 const double _kMenuHorizontalPadding = 16.0;
26 const double _kMenuVerticalPadding = 8.0; 25 const double _kMenuVerticalPadding = 8.0;
27 26
28 enum MenuState { closed, opening, open, closing } 27 enum PopupMenuStatus {
28 active,
29 inactive,
30 }
29 31
30 class PopupMenuController { 32 typedef void PopupMenuStatusChangedCallback(PopupMenuStatus status);
31
32 PopupMenuController() {
33 position = new AnimatedType<double>(0.0, end: 1.0);
34 performance = new AnimationPerformance()
35 ..variable = position
36 ..addListener(_updateState);
37 }
38
39 AnimatedType<double> position;
40 AnimationPerformance performance;
41
42 MenuState _state = MenuState.closed;
43 MenuState get state => _state;
44
45 bool get canReact => (_state == MenuState.opening) || (_state == MenuState.ope n);
46
47 void _updateState() {
48 if (position.value == 0.0) {
49 _state = MenuState.closed;
50 if (_closeCompleter != null)
51 _closeCompleter.complete();
52 return;
53 }
54
55 if (position.value == 1.0)
56 _state = MenuState.open;
57 }
58
59 Completer _closeCompleter;
60 Timer _closeTimer;
61
62 void open() {
63 if (_state != MenuState.closed)
64 return;
65 if (_closeTimer != null) {
66 _closeTimer.cancel();
67 _closeTimer = null;
68 }
69 _closeCompleter = null;
70 _state = MenuState.opening;
71 performance..duration = _kMenuOpenDuration
72 ..play();
73 }
74
75 Future close() {
76 if (_state == MenuState.closing || _state == MenuState.closed)
77 return _closeCompleter.future;
78
79 _state = MenuState.closing;
80 assert(_closeCompleter == null);
81 _closeCompleter = new Completer();
82 performance.duration = _kMenuCloseDuration;
83
84 assert(_closeTimer == null);
85 _closeTimer = new Timer(_kMenuCloseDelay, performance.reverse);
86
87 return _closeCompleter.future;
88 }
89 }
90 33
91 class PopupMenu extends AnimatedComponent { 34 class PopupMenu extends AnimatedComponent {
92 35
93 PopupMenu({ String key, this.controller, this.items, this.level }) 36 PopupMenu({
94 : super(key: key); 37 String key,
38 this.showing,
39 this.onStatusChanged,
40 this.items,
41 this.level
42 }) : super(key: key);
95 43
96 PopupMenuController controller; 44 bool showing;
45 PopupMenuStatusChangedCallback onStatusChanged;
97 List<PopupMenuItem> items; 46 List<PopupMenuItem> items;
98 int level; 47 int level;
99 48
49 AnimatedType<double> _position;
50 AnimationPerformance _performance;
51
100 void initState() { 52 void initState() {
53 _position = new AnimatedType<double>(0.0, end: 1.0);
54 _performance = new AnimationPerformance()
55 ..variable = _position
56 ..addListener(_checkForStateChanged);
57 watch(_performance);
58 _updateBoxPainter();
59 if (showing)
60 _open();
61 }
62
63 void syncFields(PopupMenu source) {
64 if (showing != source.showing) {
65 showing = source.showing;
66 if (showing)
67 _open();
68 else
69 _close();
70 }
71 onStatusChanged = source.onStatusChanged;
72 if (level != source.level) {
73 level = source.level;
74 _updateBoxPainter();
75 }
76 items = source.items;
77 super.syncFields(source);
78 }
79
80 void _updateBoxPainter() {
101 _painter = new BoxPainter(new BoxDecoration( 81 _painter = new BoxPainter(new BoxDecoration(
102 backgroundColor: Grey[50], 82 backgroundColor: Grey[50],
103 borderRadius: 2.0, 83 borderRadius: 2.0,
104 boxShadow: shadows[level])); 84 boxShadow: shadows[level]));
105 watch(controller.performance);
106 } 85 }
107 86
108 void syncFields(PopupMenu source) { 87 PopupMenuStatus get _status => _position.value != 0.0 ? PopupMenuStatus.active : PopupMenuStatus.inactive;
109 controller = source.controller; 88
110 items = source.items; 89 PopupMenuStatus _lastStatus;
111 level = source.level; 90 void _checkForStateChanged() {
112 super.syncFields(source); 91 PopupMenuStatus status = _status;
92 if (_lastStatus != null && status != _lastStatus && onStatusChanged != null)
93 onStatusChanged(status);
94 _lastStatus = status;
95 }
96
97 void _open() {
98 _performance
99 ..duration = _kMenuOpenDuration
100 ..play();
101 }
102
103 void _close() {
104 _performance
105 ..duration = _kMenuCloseDuration
106 ..reverse();
113 } 107 }
114 108
115 BoxPainter _painter; 109 BoxPainter _painter;
116 110
117 double _opacityFor(int i) { 111 double _opacityFor(int i) {
118 assert(controller.position.value != null); 112 assert(_position.value != null);
119 if (controller.position.value == null || controller.position.value == 1.0) 113 if (_position.value == null || _position.value == 1.0)
120 return 1.0; 114 return 1.0;
121 double unit = 1.0 / items.length; 115 double unit = 1.0 / items.length;
122 double duration = 1.5 * unit; 116 double duration = 1.5 * unit;
123 double start = i * unit; 117 double start = i * unit;
124 return math.max(0.0, math.min(1.0, (controller.position.value - start) / dur ation)); 118 return math.max(0.0, math.min(1.0, (_position.value - start) / duration));
125 } 119 }
126 120
127 Widget build() { 121 Widget build() {
128 int i = 0; 122 int i = 0;
129 List<Widget> children = new List.from(items.map((Widget item) { 123 List<Widget> children = new List.from(items.map((Widget item) {
130 double opacity = _opacityFor(i); 124 double opacity = _opacityFor(i);
131 return new PopupMenuItem(child: item, opacity: opacity); 125 return new PopupMenuItem(child: item, opacity: opacity);
132 })); 126 }));
133 127
134 return new Opacity( 128 return new Opacity(
135 opacity: math.min(1.0, controller.position.value * 3.0), 129 opacity: math.min(1.0, _position.value * 3.0),
136 child: new Container( 130 child: new Container(
137 margin: new EdgeDims.all(_kMenuMargin), 131 margin: new EdgeDims.all(_kMenuMargin),
138 child: new CustomPaint( 132 child: new CustomPaint(
139 callback: (sky.Canvas canvas, Size size) { 133 callback: (sky.Canvas canvas, Size size) {
140 double width = math.min(size.width, size.width * (0.5 + controller.p osition.value * 2.0)); 134 double width = math.min(size.width, size.width * (0.5 + _position.va lue * 2.0));
141 double height = math.min(size.height, size.height * controller.posit ion.value * 1.5); 135 double height = math.min(size.height, size.height * _position.value * 1.5);
142 _painter.paint(canvas, new Rect.fromLTRB(size.width - width, 0.0, wi dth, height)); 136 _painter.paint(canvas, new Rect.fromLTRB(size.width - width, 0.0, wi dth, height));
143 }, 137 },
144 child: new ConstrainedBox( 138 child: new ConstrainedBox(
145 constraints: new BoxConstraints( 139 constraints: new BoxConstraints(
146 minWidth: _kMenuMinWidth, 140 minWidth: _kMenuMinWidth,
147 maxWidth: _kMenuMaxWidth 141 maxWidth: _kMenuMaxWidth
148 ), 142 ),
149 child: new ShrinkWrapWidth( 143 child: new ShrinkWrapWidth(
150 stepWidth: _kMenuWidthStep, 144 stepWidth: _kMenuWidthStep,
151 child: new ScrollableViewport( 145 child: new ScrollableViewport(
152 child: new Container( 146 child: new Container(
153 padding: const EdgeDims.symmetric( 147 padding: const EdgeDims.symmetric(
154 horizontal: _kMenuHorizontalPadding, 148 horizontal: _kMenuHorizontalPadding,
155 vertical: _kMenuVerticalPadding 149 vertical: _kMenuVerticalPadding
156 ), 150 ),
157 child: new Block(children) 151 child: new Block(children)
158 ) 152 )
159 ) 153 )
160 ) 154 )
161 ) 155 )
162 ) 156 )
163 ) 157 )
164 ); 158 );
165 } 159 }
166 160
167 } 161 }
OLDNEW
« no previous file with comments | « sky/sdk/example/stocks/lib/stock_menu.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698