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

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: 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..198e1b4818bd5f33b1e20e489da4a09d58208c3a
--- /dev/null
+++ b/sky/sdk/lib/widgets/tabs.dart
@@ -0,0 +1,262 @@
+// 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 =
+ new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight);
+ double maxWidth = 0.0;
+ int childCount = 0;
+ RenderBox child = firstChild;
+ while (child != null) {
+ maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints));
+ ++childCount;
+ assert(child.parentData is TabBarParentData);
+ child = child.parentData.nextSibling;
+ }
+ return constraints.constrainWidth(maxWidth * childCount);
+ }
+
+ double getMaxIntrinsicWidth(BoxConstraints constraints) {
+ BoxConstraints widthConstraints =
+ new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight);
+ double maxWidth = 0.0;
+ int childCount = 0;
+ RenderBox child = firstChild;
+ while (child != null) {
+ maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints));
+ ++childCount;
+ assert(child.parentData is TabBarParentData);
+ child = child.parentData.nextSibling;
+ }
+ return constraints.constrainWidth(maxWidth * childCount);
+ }
+
+ double _getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(_kTabBarHeight);
+
+ double getMinIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints);
+
+ double getMaxIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints);
+
+ // TODO(hansmuller): track this value in the parent rather than computing it.
+ int _childCount() {
+ int childCount = 0;
+ RenderBox child = firstChild;
+ while (child != null) {
+ ++childCount;
+ assert(child.parentData is TabBarParentData);
+ child = child.parentData.nextSibling;
+ }
+ 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 = size.width / childCount;
+ BoxConstraints tabConstraints =
+ new BoxConstraints.tightFor(width: tabWidth, height: size.height);
+ double x = 0.0;
+ RenderBox child = firstChild;
+ while (child != null) {
+ child.layout(tabConstraints);
+ assert(child.parentData is TabBarParentData);
+ child.parentData.position = new Point(x, 0.0);
+ x += tabWidth;
+ child = child.parentData.nextSibling;
+ }
+ }
+
+ void hitTestChildren(HitTestResult result, { Point position }) {
+ defaultHitTestChildren(result, position: position);
+ }
+
+ void _paintIndicator(RenderCanvas canvas, RenderBox selectedTab) {
+ var size = new Size(selectedTab.size.width, _kTabIndicatorHeight);
+ var point = new Point(selectedTab.parentData.position.x, _kTabHeight);
+ Rect rect = new Rect.fromPointAndSize(point, size);
+ // TODO(hansmuller): indicator color should be based on the theme.
+ canvas.drawRect(rect, new Paint()..color = White);
+ }
+
+ void paint(RenderCanvas canvas) {
+ Rect rect = new Rect.fromSize(size);
+ canvas.drawRect(rect, new Paint()..color = Blue[500]);
+
+ int index = 0;
+ RenderBox child = firstChild;
+ while (child != null) {
+ assert(child.parentData is TabBarParentData);
+ canvas.paintChild(child, child.parentData.position);
+ if (index++ == selectedIndex)
+ _paintIndicator(canvas, child);
+ child = child.parentData.nextSibling;
+ }
+ }
+}
+
+class TabBarWrapper extends MultiChildRenderObjectWrapper {
+ TabBarWrapper(List<Widget> children, 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);
+
+ final List<TabLabel> labels;
+ final int selectedIndex;
+ final SelectedIndexChanged onChanged;
+
+ void _handleTap(int tabIndex) {
+ if (tabIndex != selectedIndex && onChanged != null)
+ onChanged(tabIndex);
+ }
+
+ 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