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

Unified 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: Updates per Ian's feedback 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sky/sdk/lib/rendering/box.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/sdk/lib/widgets/tabs.dart
diff --git a/sky/sdk/lib/widgets/tabs.dart b/sky/sdk/lib/widgets/tabs.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2dcec21919b7b971406c0b5f4b5bca62b338eb94
--- /dev/null
+++ b/sky/sdk/lib/widgets/tabs.dart
@@ -0,0 +1,267 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:math' as math;
+import 'dart:sky' as sky;
+
+import 'package:sky/painting/text_style.dart';
+import 'package:sky/rendering/box.dart';
+import 'package:sky/rendering/object.dart';
+import 'package:sky/theme/colors.dart';
+import 'package:sky/widgets/basic.dart';
+import 'package:sky/widgets/icon.dart';
+import 'package:sky/widgets/ink_well.dart';
+import 'package:sky/widgets/widget.dart';
+
+typedef void SelectedIndexChanged(int selectedIndex);
+
+const double _kTabHeight = 46.0;
+const double _kTabIndicatorHeight = 2.0;
+const double _kTabBarHeight = _kTabHeight + _kTabIndicatorHeight;
+const double _kMinTabWidth = 72.0;
+
+class TabBarParentData extends BoxParentData with
+ ContainerParentDataMixin<RenderBox> { }
+
+class RenderTabBar extends RenderBox with
+ ContainerRenderObjectMixin<RenderBox, TabBarParentData>,
+ RenderBoxContainerDefaultsMixin<RenderBox, TabBarParentData> {
+
+ int _selectedIndex;
+ int get selectedIndex => _selectedIndex;
+ void set selectedIndex(int value) {
+ if (_selectedIndex != value) {
+ _selectedIndex = value;
+ markNeedsPaint();
+ }
+ }
+
+ void setParentData(RenderBox child) {
+ if (child.parentData is! TabBarParentData) {
+ child.parentData = new TabBarParentData();
+ }
+ }
+
+ double getMinIntrinsicWidth(BoxConstraints constraints) {
+ BoxConstraints widthConstraints = constraints.widthConstraints();
+ double maxWidth = 0.0;
+ int childCount = 0;
+ for (RenderBox child = firstChild; child != null; child = child.parentData.nextSibling) {
+ maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints));
+ ++childCount;
+ }
+ return maxWidth * childCount.toDouble();
+ }
+
+ double getMaxIntrinsicWidth(BoxConstraints constraints) {
+ BoxConstraints widthConstraints = constraints.widthConstraints();
+ double maxWidth = 0.0;
+ int childCount = 0;
+ for (RenderBox child = firstChild; child != null; child = child.parentData.nextSibling) {
+ maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints));
+ ++childCount;
+ }
+ return maxWidth * childCount.toDouble();
+ }
+
+ double _getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(_kTabBarHeight);
+
+ double getMinIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints);
+
+ double getMaxIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints);
+
+ int _childCount() {
+ int childCount = 0;
+ for (RenderBox child = firstChild; child != null; child = child.parentData.nextSibling) {
+ ++childCount;
+ }
+ return childCount;
+ }
+
+ void performLayout() {
+ assert(constraints is BoxConstraints);
+
+ size = constraints.constrain(new Size(constraints.maxWidth, _kTabBarHeight));
+ assert(size.width < double.INFINITY);
+ assert(size.height < double.INFINITY);
+
+ int childCount = _childCount();
+ if (childCount == 0) return;
+
+ double tabWidth = constraints.constrainWidth(constraints.maxWidth) / childCount.toDouble();
+ BoxConstraints tabConstraints =
+ new BoxConstraints.tightFor(width: tabWidth, height: size.height);
+ double x = 0.0;
+ for (RenderBox child = firstChild; child != null; child = child.parentData.nextSibling) {
+ child.layout(tabConstraints, parentUsesSize: true);
abarth-chromium 2015/06/25 18:25:49 Rather than passing |parentUsesSize: true| here, w
hansmuller 2015/06/25 19:45:50 Sorry, I wasn't disagreeing with this feedback; It
+ assert(child.parentData is TabBarParentData);
+ child.parentData.position = new Point(x, 0.0);
+ x += child.size.width;
+ }
+ }
+
+ void hitTestChildren(HitTestResult result, { Point position }) {
+ defaultHitTestChildren(result, position: position);
+ }
+
+ void _paintBackground(RenderObjectDisplayList canvas) {
+ // TODO(hansmuller): background color should be based on the theme.
+ Paint paint = new Paint()
+ ..color = Blue[500]
+ ..setStyle(sky.PaintingStyle.fill);
+ Rect rect = new Rect.fromSize(size);
+ canvas.drawRect(rect, paint);
+ }
+
+ void _paintIndicator(RenderObjectDisplayList canvas, RenderBox selectedTab) {
+ var size = new Size(selectedTab.size.width, 2.0);
+ var point = new Point(selectedTab.parentData.position.x, 46.0);
+ Rect rect = new Rect.fromPointAndSize(point, size);
+ // TODO(hansmuller): indicator color should be based on the theme.
+ Paint paint = new Paint()
+ ..color = White
+ ..setStyle(sky.PaintingStyle.fill);
+ canvas.drawRect(rect, paint);
+ }
+
+ void paint(RenderObjectDisplayList canvas) {
+ _paintBackground(canvas);
+
+ var index = 0;
+ for (RenderBox child = firstChild; child != null; child = child.parentData.nextSibling) {
+ assert(child.parentData is TabBarParentData);
+ canvas.paintChild(child, child.parentData.position);
+ if (index++ == selectedIndex) _paintIndicator(canvas, child);
+ }
+ }
+}
+
+class TabBarWrapper extends MultiChildRenderObjectWrapper {
+ TabBarWrapper(List<Widget> children, int this.selectedIndex, { String key })
+ : super(key: key, children: children);
+
+ final int selectedIndex;
+
+ RenderTabBar get root => super.root;
+ RenderTabBar createNode() => new RenderTabBar();
+
+ void syncRenderObject(Widget old) {
+ super.syncRenderObject(old);
+ root.selectedIndex = selectedIndex;
+ }
+}
+
+class TabLabel {
+ const TabLabel({ this.text, this.icon });
+
+ final String text;
+ final String icon;
+}
+
+class Tab extends Component {
+ Tab({
+ String key,
+ this.label,
+ this.selected: false
+ }) : super(key: key) {
+ assert(label.text != null || label.icon != null);
+ }
+
+ final TabLabel label;
+ final bool selected;
+
+ // TODO(hansmuller): use themes here.
+ static const TextStyle selectedStyle = const TextStyle(color: const Color(0xFFFFFFFF));
+ static const TextStyle style = const TextStyle(color: const Color(0xB2FFFFFF));
+
+ Widget _buildLabelText() {
+ assert(label.text != null);
+ return new Text(label.text, style: style);
+ }
+
+ Widget _buildLabelIcon() {
+ assert(label.icon != null);
+ return new Icon(type: label.icon, size: 24);
+ }
+
+ Widget build() {
+ Widget labelContents;
+ if (label.icon == null) {
+ labelContents = _buildLabelText();
+ } else if (label.text == null) {
+ labelContents = _buildLabelIcon();
+ } else {
+ labelContents = new Flex(
+ <Widget>[_buildLabelText(), _buildLabelIcon()],
+ justifyContent: FlexJustifyContent.center,
+ alignItems: FlexAlignItems.center,
+ direction: FlexDirection.vertical
+ );
+ }
+
+ Widget highlightedLabel = new Opacity(
+ child: labelContents,
+ opacity: selected ? 1.0 : 0.7
+ );
+
+ Container centeredLabel = new Container(
+ child: new Center(child: highlightedLabel),
+ constraints: new BoxConstraints(minWidth: _kMinTabWidth)
+ );
+
+ return new InkWell(child: centeredLabel);
+ }
+}
+
+class TabBar extends Component {
+ TabBar({
+ String key,
+ this.labels,
+ this.selectedIndex: 0,
+ this.onChanged
+ }) : super(key: key, stateful: true);
+
+ List<TabLabel> labels;
+ int selectedIndex;
+ SelectedIndexChanged onChanged;
+
+ void syncFields(TabBar source) {
+ labels = source.labels;
+ selectedIndex = source.selectedIndex;
+ onChanged = source.onChanged;
+ super.syncFields(source);
+ }
+
+ void _handleTap(int tabIndex) {
+ if (tabIndex != selectedIndex) {
+ setState(() {
+ selectedIndex = tabIndex;
+ });
+ if (onChanged != null) onChanged(selectedIndex);
+ }
+ }
+
+ Widget _toTab(TabLabel label, int tabIndex) {
+ Tab tab = new Tab(
+ label: label,
+ selected: tabIndex == selectedIndex,
+ key: label.text == null ? label.icon : label.text
+ );
+ return new Listener(
+ child: tab,
+ onGestureTap: (_) => _handleTap(tabIndex)
+ );
+ }
+
+ Widget build() {
+ assert(labels != null && labels.isNotEmpty);
+ List<Widget> tabs = <Widget>[];
+ for (int tabIndex = 0; tabIndex < labels.length; tabIndex++) {
+ tabs.add(_toTab(labels[tabIndex], tabIndex));
+ }
+ return new TabBarWrapper(tabs, selectedIndex);
+ }
+}
+
+
« 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