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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/CascadingStripStacker.java

Issue 1836453003: Use a scrollable tab strip on tablets at small widths (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add tests Created 4 years, 8 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
Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/CascadingStripStacker.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/CascadingStripStacker.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/CascadingStripStacker.java
new file mode 100644
index 0000000000000000000000000000000000000000..555b21c3d29588f3ae2be4660402d08c579df2b0
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/CascadingStripStacker.java
@@ -0,0 +1,183 @@
+// Copyright 2016 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.
+
+package org.chromium.chrome.browser.compositor.overlays.strip;
+
+import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.ui.base.LocalizationUtils;
+
+/**
+ * A stacker that tells the {@link StripLayoutHelper} how to layer the tabs for the
+ * {@link StaticLayout} when the available window width is >= 600dp. Tabs will be stacked with the
+ * focused tab in front with tabs cascading back to each side.
+ */
+public class CascadingStripStacker extends StripStacker {
+ @Override
+ public void setTabOffsets(int selectedIndex, StripLayoutTab[] indexOrderedTabs,
+ float tabStackWidth, int maxTabsToStack, float tabOverlapWidth, float stripLeftMargin,
+ float stripRightMargin, float stripWidth, boolean inReorderMode) {
+ // 1. Calculate the size of the selected tab. This is used later to figure out how
+ // occluded the tabs are.
+ final StripLayoutTab selTab = selectedIndex >= 0 ? indexOrderedTabs[selectedIndex] : null;
+ final float selTabWidth = selTab != null ? selTab.getWidth() : 0;
+ final float selTabVisibleSize = selTabWidth - tabStackWidth - tabOverlapWidth;
+
+ for (int i = 0; i < indexOrderedTabs.length; i++) {
+ StripLayoutTab tab = indexOrderedTabs[i];
+
+ float posX = tab.getIdealX();
+
+ // 2. Calculate how many tabs are stacked on the left or the right, giving us an idea
+ // of where we can stack this current tab.
+ int leftStackCount = (i < selectedIndex) ? Math.min(i, maxTabsToStack)
+ : Math.min(maxTabsToStack, selectedIndex)
+ + Math.min(maxTabsToStack, i - selectedIndex);
+
+ int rightStackCount = (i >= selectedIndex)
+ ? Math.min(indexOrderedTabs.length - 1 - i, maxTabsToStack)
+ : Math.min(indexOrderedTabs.length - 1 - selectedIndex, maxTabsToStack)
+ + Math.min(selectedIndex - i, maxTabsToStack);
+
+ if (LocalizationUtils.isLayoutRtl()) {
+ int oldLeft = leftStackCount;
+ leftStackCount = rightStackCount;
+ rightStackCount = oldLeft;
+ }
+
+ // 3. Calculate the proper draw position for the tab. Clamp based on stacking
+ // rules.
+ float minDrawX = tabStackWidth * leftStackCount + stripLeftMargin;
+ float maxDrawX = stripWidth - tabStackWidth * rightStackCount - stripRightMargin;
+
+ float drawX =
+ MathUtils.clamp(posX + tab.getOffsetX(), minDrawX, maxDrawX - tab.getWidth());
+
+ // TODO(dtrainor): Don't set drawX if the tab is closing?
+ tab.setDrawX(drawX);
+ tab.setDrawY(tab.getOffsetY());
+
+ // 4. Calculate how visible this tab is.
+ float visiblePercentage = 1.f;
+ if (i != selectedIndex) {
+ final float effectiveTabWidth = Math.max(tab.getWidth(), 1.f);
+ final boolean leftStack =
+ LocalizationUtils.isLayoutRtl() ? i > selectedIndex : i < selectedIndex;
+ final float minVisible = !leftStack ? minDrawX + selTabVisibleSize : minDrawX;
+ final float maxVisible = leftStack ? maxDrawX - selTabVisibleSize : maxDrawX;
+
+ final float clippedTabWidth =
+ Math.min(posX + effectiveTabWidth, maxVisible) - Math.max(posX, minVisible);
+ visiblePercentage = MathUtils.clamp(clippedTabWidth / effectiveTabWidth, 0.f, 1.f);
+ }
+ tab.setVisiblePercentage(visiblePercentage);
+
+ // 5. Calculate which index we start sliding content for.
+ // When reordering, we don't want to slide the content of the adjacent tabs.
+ int contentOffsetIndex = inReorderMode ? selectedIndex + 1 : selectedIndex;
+
+ // 6. Calculate how much the tab is overlapped on the left side or right for RTL.
+ float hiddenAmount = 0.f;
+ if (i > contentOffsetIndex && i > 0) {
+ // 6.a. Get the effective right edge of the previous tab.
+ final StripLayoutTab prevTab = indexOrderedTabs[i - 1];
+ final float prevLayoutWidth =
+ (prevTab.getWidth() - tabOverlapWidth) * prevTab.getWidthWeight();
+ float prevTabRight = prevTab.getDrawX();
+ if (!LocalizationUtils.isLayoutRtl()) prevTabRight += prevLayoutWidth;
+
+ // 6.b. Subtract our current draw X from the previous tab's right edge and
+ // get the percentage covered.
+ hiddenAmount = Math.max(prevTabRight - drawX, 0);
+ if (LocalizationUtils.isLayoutRtl()) {
+ // Invert The amount because we're RTL.
+ hiddenAmount = prevLayoutWidth - hiddenAmount;
+ }
+ }
+
+ tab.setContentOffsetX(hiddenAmount);
+ }
+ }
+
+ @Override
+ public float computeNewTabButtonOffset(StripLayoutTab[] indexOrderedTabs,
+ float tabOverlapWidth, float stripLeftMargin, float stripRightMargin, float stripWidth,
+ float newTabButtonWidth) {
+ return LocalizationUtils.isLayoutRtl()
+ ? computeNewTabButtonOffsetRtl(indexOrderedTabs, tabOverlapWidth, stripLeftMargin,
+ stripRightMargin, stripWidth, newTabButtonWidth)
+ : computeNewTabButtonOffsetLtr(indexOrderedTabs, tabOverlapWidth,
+ stripLeftMargin, stripRightMargin, stripWidth);
+ }
+
+ @Override
+ public void performOcclusionPass(int selectedIndex, StripLayoutTab[] indexOrderedTabs,
+ float stripWidth) {
+ for (int i = 1; i < indexOrderedTabs.length; i++) {
+ StripLayoutTab prevTab = indexOrderedTabs[i - 1];
+ StripLayoutTab currTab = indexOrderedTabs[i];
+
+ if ((int) prevTab.getDrawY() == (int) currTab.getDrawY()
+ && (int) prevTab.getDrawX() == (int) currTab.getDrawX()) {
+ if (i <= selectedIndex) {
+ prevTab.setVisible(false);
+ } else if (i > selectedIndex) {
+ currTab.setVisible(false);
+ }
+ } else if ((int) prevTab.getDrawX() != (int) currTab.getDrawX()) {
+ if (i <= selectedIndex) {
+ prevTab.setVisible(true);
+ } else if (i > selectedIndex) {
+ currTab.setVisible(true);
+ }
+ }
+
+ if (i == selectedIndex) currTab.setVisible(true);
+
+ // If index 0 is selected, this line is required to set its visibility correctly.
+ if (i - 1 == selectedIndex) prevTab.setVisible(true);
+ }
+ }
+
+ private float computeNewTabButtonOffsetLtr(StripLayoutTab[] indexOrderedTabs,
+ float tabOverlapWidth, float stripLeftMargin, float stripRightMargin,
+ float stripWidth) {
+ float rightEdge = stripLeftMargin;
+
+ for (int i = 0; i < indexOrderedTabs.length; i++) {
+ StripLayoutTab tab = indexOrderedTabs[i];
+ float layoutWidth = (tab.getWidth() - tabOverlapWidth) * tab.getWidthWeight();
+ rightEdge = Math.max(tab.getDrawX() + layoutWidth, rightEdge);
+ }
+
+ rightEdge = Math.min(rightEdge + tabOverlapWidth, stripWidth - stripRightMargin);
+
+ // Adjust the right edge by the tab overlap width so that the new tab button is nestled
+ // closer to the tab.
+ rightEdge -= tabOverlapWidth / 2;
+
+ // The draw X position for the new tab button is the rightEdge of the tab strip.
+ return rightEdge;
+ }
+
+ private float computeNewTabButtonOffsetRtl(StripLayoutTab[] indexOrderedTabs,
+ float tabOverlapWidth, float stripLeftMargin, float stripRightMargin, float stripWidth,
+ float newTabButtonWidth) {
+ float leftEdge = stripWidth - stripRightMargin;
+
+ for (int i = 0; i < indexOrderedTabs.length; i++) {
+ StripLayoutTab tab = indexOrderedTabs[i];
+ leftEdge = Math.min(tab.getDrawX(), leftEdge);
+ }
+
+ leftEdge = Math.max(leftEdge, stripLeftMargin);
+
+ // Adjust the left edge by the tab overlap width so that the new tab button is nestled
+ // closer to the tab.
+ leftEdge += tabOverlapWidth / 2;
+
+ // The draw X position for the new tab button is the left edge of the tab strip minus
+ // the new tab button width.
+ return leftEdge - newTabButtonWidth;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698