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

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

Issue 1205953002: Version 0 of TabLabel, Tab, and TabBar components (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 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/lib/rendering/box.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
(Empty)
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
3 // found in the LICENSE file.
4
5 import 'dart:math' as math;
6 import 'dart:sky' as sky;
7
8 import 'package:sky/painting/text_style.dart';
9 import 'package:sky/rendering/box.dart';
10 import 'package:sky/rendering/object.dart';
11 import 'package:sky/theme/colors.dart';
12 import 'package:sky/widgets/basic.dart';
13 import 'package:sky/widgets/icon.dart';
14 import 'package:sky/widgets/ink_well.dart';
15 import 'package:sky/widgets/widget.dart';
16
17 typedef void SelectedIndexChanged(int selectedIndex);
18
19 const double _kTabHeight = 46.0;
20 const double _kTabIndicatorHeight = 2.0;
21 const double _kTabBarHeight = _kTabHeight + _kTabIndicatorHeight;
22 const double _kMinTabWidth = 72.0;
23
24 class TabBarParentData extends BoxParentData with
25 ContainerParentDataMixin<RenderBox> { }
26
27 class RenderTabBar extends RenderBox with
28 ContainerRenderObjectMixin<RenderBox, TabBarParentData>,
29 RenderBoxContainerDefaultsMixin<RenderBox, TabBarParentData> {
30
31 int _selectedIndex;
32 int get selectedIndex => _selectedIndex;
33 void set selectedIndex(int value) {
34 if (_selectedIndex != value) {
35 _selectedIndex = value;
36 markNeedsPaint();
37 }
38 }
39
40 void setParentData(RenderBox child) {
41 if (child.parentData is! TabBarParentData)
42 child.parentData = new TabBarParentData();
43 }
44
45 double getMinIntrinsicWidth(BoxConstraints constraints) {
46 BoxConstraints widthConstraints =
47 new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraint s.maxHeight);
48 double maxWidth = 0.0;
49 int childCount = 0;
50 RenderBox child = firstChild;
51 while (child != null) {
52 maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints) );
53 ++childCount;
54 assert(child.parentData is TabBarParentData);
55 child = child.parentData.nextSibling;
56 }
57 return constraints.constrainWidth(maxWidth * childCount);
58 }
59
60 double getMaxIntrinsicWidth(BoxConstraints constraints) {
61 BoxConstraints widthConstraints =
62 new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraint s.maxHeight);
63 double maxWidth = 0.0;
64 int childCount = 0;
65 RenderBox child = firstChild;
66 while (child != null) {
67 maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints) );
68 ++childCount;
69 assert(child.parentData is TabBarParentData);
70 child = child.parentData.nextSibling;
71 }
72 return constraints.constrainWidth(maxWidth * childCount);
73 }
74
75 double _getIntrinsicHeight(BoxConstraints constraints) => constraints.constrai nHeight(_kTabBarHeight);
76
77 double getMinIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeigh t(constraints);
78
79 double getMaxIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeigh t(constraints);
80
81 // TODO(hansmuller): track this value in the parent rather than computing it.
82 int _childCount() {
83 int childCount = 0;
84 RenderBox child = firstChild;
85 while (child != null) {
86 ++childCount;
87 assert(child.parentData is TabBarParentData);
88 child = child.parentData.nextSibling;
89 }
90 return childCount;
91 }
92
93 void performLayout() {
94 assert(constraints is BoxConstraints);
95
96 size = constraints.constrain(new Size(constraints.maxWidth, _kTabBarHeight)) ;
97 assert(size.width < double.INFINITY);
98 assert(size.height < double.INFINITY);
99
100 int childCount = _childCount();
101 if (childCount == 0)
102 return;
103
104 double tabWidth = size.width / childCount;
105 BoxConstraints tabConstraints =
106 new BoxConstraints.tightFor(width: tabWidth, height: size.height);
107 double x = 0.0;
108 RenderBox child = firstChild;
109 while (child != null) {
110 child.layout(tabConstraints);
111 assert(child.parentData is TabBarParentData);
112 child.parentData.position = new Point(x, 0.0);
113 x += tabWidth;
114 child = child.parentData.nextSibling;
115 }
116 }
117
118 void hitTestChildren(HitTestResult result, { Point position }) {
119 defaultHitTestChildren(result, position: position);
120 }
121
122 void _paintIndicator(RenderCanvas canvas, RenderBox selectedTab) {
123 var size = new Size(selectedTab.size.width, _kTabIndicatorHeight);
124 var point = new Point(selectedTab.parentData.position.x, _kTabHeight);
125 Rect rect = new Rect.fromPointAndSize(point, size);
126 // TODO(hansmuller): indicator color should be based on the theme.
127 canvas.drawRect(rect, new Paint()..color = White);
128 }
129
130 void paint(RenderCanvas canvas) {
131 Rect rect = new Rect.fromSize(size);
132 canvas.drawRect(rect, new Paint()..color = Blue[500]);
133
134 int index = 0;
135 RenderBox child = firstChild;
136 while (child != null) {
137 assert(child.parentData is TabBarParentData);
138 canvas.paintChild(child, child.parentData.position);
139 if (index++ == selectedIndex)
140 _paintIndicator(canvas, child);
141 child = child.parentData.nextSibling;
142 }
143 }
144 }
145
146 class TabBarWrapper extends MultiChildRenderObjectWrapper {
147 TabBarWrapper(List<Widget> children, this.selectedIndex, { String key })
148 : super(key: key, children: children);
149
150 final int selectedIndex;
151
152 RenderTabBar get root => super.root;
153 RenderTabBar createNode() => new RenderTabBar();
154
155 void syncRenderObject(Widget old) {
156 super.syncRenderObject(old);
157 root.selectedIndex = selectedIndex;
158 }
159 }
160
161 class TabLabel {
162 const TabLabel({ this.text, this.icon });
163
164 final String text;
165 final String icon;
166 }
167
168 class Tab extends Component {
169 Tab({
170 String key,
171 this.label,
172 this.selected: false
173 }) : super(key: key) {
174 assert(label.text != null || label.icon != null);
175 }
176
177 final TabLabel label;
178 final bool selected;
179
180 // TODO(hansmuller): use themes here.
181 static const TextStyle selectedStyle = const TextStyle(color: const Color(0xFF FFFFFF));
182 static const TextStyle style = const TextStyle(color: const Color(0xB2FFFFFF)) ;
183
184 Widget _buildLabelText() {
185 assert(label.text != null);
186 return new Text(label.text, style: style);
187 }
188
189 Widget _buildLabelIcon() {
190 assert(label.icon != null);
191 return new Icon(type: label.icon, size: 24);
192 }
193
194 Widget build() {
195 Widget labelContents;
196 if (label.icon == null) {
197 labelContents = _buildLabelText();
198 } else if (label.text == null) {
199 labelContents = _buildLabelIcon();
200 } else {
201 labelContents = new Flex(
202 <Widget>[_buildLabelText(), _buildLabelIcon()],
203 justifyContent: FlexJustifyContent.center,
204 alignItems: FlexAlignItems.center,
205 direction: FlexDirection.vertical
206 );
207 }
208
209 Widget highlightedLabel = new Opacity(
210 child: labelContents,
211 opacity: selected ? 1.0 : 0.7
212 );
213
214 Container centeredLabel = new Container(
215 child: new Center(child: highlightedLabel),
216 constraints: new BoxConstraints(minWidth: _kMinTabWidth)
217 );
218
219 return new InkWell(child: centeredLabel);
220 }
221 }
222
223 class TabBar extends Component {
224 TabBar({
225 String key,
226 this.labels,
227 this.selectedIndex: 0,
228 this.onChanged
229 }) : super(key: key);
230
231 final List<TabLabel> labels;
232 final int selectedIndex;
233 final SelectedIndexChanged onChanged;
234
235 void _handleTap(int tabIndex) {
236 if (tabIndex != selectedIndex && onChanged != null)
237 onChanged(tabIndex);
238 }
239
240 Widget _toTab(TabLabel label, int tabIndex) {
241 Tab tab = new Tab(
242 label: label,
243 selected: tabIndex == selectedIndex,
244 key: label.text == null ? label.icon : label.text
245 );
246 return new Listener(
247 child: tab,
248 onGestureTap: (_) => _handleTap(tabIndex)
249 );
250 }
251
252 Widget build() {
253 assert(labels != null && labels.isNotEmpty);
254 List<Widget> tabs = <Widget>[];
255 for (int tabIndex = 0; tabIndex < labels.length; tabIndex++) {
256 tabs.add(_toTab(labels[tabIndex], tabIndex));
257 }
258 return new TabBarWrapper(tabs, selectedIndex);
259 }
260 }
261
262
OLDNEW
« no previous file with comments | « sky/sdk/lib/rendering/box.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698