15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_strip.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windowsx.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iterator> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/defaults.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/host_desktop.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/view_ids.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_strip_controller.h" 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_strip_observer.h" 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/ui/views/touch_uma/touch_uma.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h" 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/default_theme_provider.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/drag_drop_types.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/layout.h" 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/models/list_selection_model.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_container.h" 41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/throb_animation.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/gfx/display.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_operations.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/path.h" 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/rect_conversions.h" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h" 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/image_view.h" 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/mouse_watcher_view_host.h" 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/views/rect_based_targeting_utils.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/view_model_utils.h" 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/root_view.h" 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/non_client_view.h" 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/win/hwnd_util.h" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/monitor_win.h" 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/views/win/hwnd_util.h" 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/util/win8_util.h" 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ui::DropTargetEvent; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTabStripAnimationVSlop = 40; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Inactive tabs in a native frame are slightly transparent. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kNativeFrameInactiveTabAlpha = 200; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If there are multiple tabs selected then make non-selected inactive tabs 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// even more transparent. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kNativeFrameInactiveTabAlphaMultiSelection = 150; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Alpha applied to all elements save the selected tabs. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kInactiveTabAndNewTabButtonAlphaAsh = 230; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kInactiveTabAndNewTabButtonAlpha = 255; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Inverse ratio of the width of a tab edge to the width of the tab. When 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// hovering over the left or right edge of a tab, the drop indicator will 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// point between tabs. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTabEdgeRatioInverse = 4; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Size of the drop indicator. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int drop_indicator_width; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int drop_indicator_height; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline int Round(double x) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Why oh why is this not in a standard header? 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(floor(x + 0.5)); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Max number of stacked tabs. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxStackedCount = 4; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding between stacked tabs. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kStackedPadding = 6; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See UpdateLayoutTypeFromMouseEvent() for a description of these. 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if !defined(USE_ASH) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMouseMoveTimeMS = 200; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMouseMoveCountBeforeConsiderReal = 3; 1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount of time we delay before resizing after a close from a touch. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTouchResizeLayoutTimeMS = 2000; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Horizontal offset for the new tab button to bring it closer to the 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rightmost tab. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int newtab_button_h_offset() { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = -11; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = -13; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Vertical offset for the new tab button to bring it closer to the 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// rightmost tab. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int newtab_button_v_offset() { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 7; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 8; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount the left edge of a tab is offset from the rectangle of the tab's 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// favicon/title/close box. Related to the width of IDR_TAB_ACTIVE_LEFT. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Affects the size of the "V" between adjacent tabs. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int tab_h_offset() { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = -26; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) value = -34; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The size of the new tab button must be hardcoded because we need to be 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// able to lay it out before we are able to get its image from the 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ui::ThemeProvider. It also makes sense to do this, because the size of the 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// new tab button should not need to be calculated dynamically. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int newtab_button_asset_width() { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 34; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 46; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int newtab_button_asset_height() { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 18; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 24; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount to adjust the clip by when the tab is stacked before the active index. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int stacked_tab_left_clip() { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 20; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 26; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount to adjust the clip by when the tab is stacked after the active index. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int stacked_tab_right_clip() { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int value = -1; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == -1) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (ui::GetDisplayLayout()) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_DESKTOP: 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 20; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::LAYOUT_TOUCH: 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = 26; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return value; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)base::string16 GetClipboardText() { 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!ui::Clipboard::IsSupportedClipboardType(ui::CLIPBOARD_TYPE_SELECTION)) 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::string16(); 245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); 246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(clipboard); 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::string16 clipboard_text; 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &clipboard_text); 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return clipboard_text; 250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Animation delegate used when a dragged tab is released. When done sets the 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dragging state to false. 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ResetDraggingStateDelegate 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public views::BoundsAnimator::OwnedAnimationDelegate { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit ResetDraggingStateDelegate(Tab* tab) : tab_(tab) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_->set_dragging(false); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_->set_dragging(false); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab_; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If |dest| contains the point |point_in_source| the event handler from |dest| 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is returned. Otherwise NULL is returned. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* ConvertPointToViewAndGetEventHandler( 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* source, 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* dest, 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Point& point_in_source) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point dest_point(point_in_source); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToTarget(source, dest, &dest_point); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dest->HitTestPoint(dest_point) ? 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest->GetEventHandlerForPoint(dest_point) : NULL; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Gets a tooltip handler for |point_in_source| from |dest|. Note that |dest| 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// should return NULL if it does not contain the point. 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::View* ConvertPointToViewAndGetTooltipHandler( 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* source, 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* dest, 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const gfx::Point& point_in_source) { 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point dest_point(point_in_source); 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View::ConvertPointToTarget(source, dest, &dest_point); 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return dest->GetTooltipHandlerForPoint(dest_point); 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TabDragController::EventSource EventSourceFromEvent( 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::LocatedEvent& event) { 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return event.IsGestureEvent() ? TabDragController::EVENT_SOURCE_TOUCH : 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabDragController::EVENT_SOURCE_MOUSE; 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NewTabButton 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A subclass of button that hit-tests to the shape of the new tab button and 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// does custom drawing. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NewTabButton : public views::ImageButton { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NewTabButton(TabStrip* tab_strip, views::ButtonListener* listener); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~NewTabButton(); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the background offset used to match the background image to the frame 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // image. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_background_offset(const gfx::Point& offset) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_offset_ = offset; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from views::View: 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool HasHitTestMask() const OVERRIDE; 3250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) virtual void GetHitTestMask(HitTestSource source, 3260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) gfx::Path* path) const OVERRIDE; 3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Overridden from ui::EventHandler: 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ShouldUseNativeFrame() const; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia GetBackgroundImage(views::CustomButton::ButtonState state, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor) const; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia GetImageForState(views::CustomButton::ButtonState state, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor) const; 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::ImageSkia GetImageForScale(ui::ScaleFactor scale_factor) const; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Tab strip that contains this button. 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStrip* tab_strip_; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The offset used to paint the background image. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point background_offset_; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // were we destroyed? 35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool* destroyed_; 35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(NewTabButton); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabButton::NewTabButton(TabStrip* tab_strip, views::ButtonListener* listener) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : views::ImageButton(listener), 35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) tab_strip_(tab_strip), 35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) destroyed_(NULL) { 359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) set_triggerable_event_flags(triggerable_event_flags() | 361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ui::EF_MIDDLE_MOUSE_BUTTON); 362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NewTabButton::~NewTabButton() { 36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (destroyed_) 36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *destroyed_ = true; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabButton::HasHitTestMask() const { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the button is sized to the top of the tab strip we want the user to 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be able to click on complete bounds, and so don't return a custom hit 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mask. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !tab_strip_->SizeTabButtonToTopOfTabStrip(); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void NewTabButton::GetHitTestMask(HitTestSource source, gfx::Path* path) const { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(path); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkScalar w = SkIntToScalar(width()); 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkScalar v_offset = SkIntToScalar(newtab_button_v_offset()); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These values are defined by the shape of the new tab image. Should that 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // image ever change, these values will need to be updated. They're so 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // custom it's not really worth defining constants for. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These values are correct for regular and USE_ASH versions of the image. 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->moveTo(0, v_offset + 1); 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(w - 7, v_offset + 1); 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(w - 4, v_offset + 4); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(w, v_offset + 16); 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(w - 1, v_offset + 17); 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(7, v_offset + 17); 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(4, v_offset + 13); 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path->lineTo(0, v_offset + 1); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path->close(); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabButton::OnMouseReleased(const ui::MouseEvent& event) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.IsOnlyRightMouseButton()) { 401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Point point = event.location(); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(this, &point); 40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool destroyed = false; 40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) destroyed_ = &destroyed; 4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gfx::ShowSystemMenuAtPoint(views::HWNDForView(this), point); 4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (destroyed) 4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return; 4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) destroyed_ = NULL; 4107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) SetState(views::CustomButton::STATE_NORMAL); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::ImageButton::OnMouseReleased(event); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NewTabButton::OnPaint(gfx::Canvas* canvas) { 41868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::ImageSkia image = 41968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) GetImageForScale(ui::GetSupportedScaleFactor(canvas->image_scale())); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(image, 0, height() - image.height()); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NewTabButton::OnGestureEvent(ui::GestureEvent* event) { 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Consume all gesture events here so that the parent (Tab) does not 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start consuming gestures. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::ImageButton::OnGestureEvent(event); 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->SetHandled(); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NewTabButton::ShouldUseNativeFrame() const { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetWidget() && 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWidget()->GetTopLevelWidget()->ShouldUseNativeFrame(); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia NewTabButton::GetBackgroundImage( 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::CustomButton::ButtonState state, 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor) const { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int background_id = 0; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShouldUseNativeFrame()) { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_id = IDR_THEME_TAB_BACKGROUND_V; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tab_strip_->controller()->IsIncognito()) { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (win8::IsSingleWindowMetroMode()) { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_id = IDR_THEME_TAB_BACKGROUND_V; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_id = IDR_THEME_TAB_BACKGROUND; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int alpha = 0; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (state) { 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case views::CustomButton::STATE_NORMAL: 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case views::CustomButton::STATE_HOVERED: 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alpha = ShouldUseNativeFrame() ? kNativeFrameInactiveTabAlpha : 255; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case views::CustomButton::STATE_PRESSED: 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alpha = 145; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* mask = 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetThemeProvider()->GetImageSkiaNamed(IDR_NEWTAB_BUTTON_MASK); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height = mask->height(); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = mask->width(); 46968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) float scale = ui::GetImageScale(scale_factor); 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The canvas and mask has to use the same scale factor. 47168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!mask->HasRepresentation(scale)) 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scale_factor = ui::SCALE_FACTOR_100P; 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 47468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Canvas canvas(gfx::Size(width, height), scale, false); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For custom images the background starts at the top of the tab strip. 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise the background starts at the top of the frame. 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* background = 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetThemeProvider()->GetImageSkiaNamed(background_id); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset_y = GetThemeProvider()->HasCustomImage(background_id) ? 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 : background_offset_.y(); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The new tab background is mirrored in RTL mode, but the theme background 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should never be mirrored. Mirror it here to compensate. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float x_scale = 1.0f; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = GetMirroredX() + background_offset_.x(); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL()) { 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x_scale = -1.0f; 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Offset by |width| such that the same region is painted as if there was no 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // flip. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x += width; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.TileImageInt(*background, x, newtab_button_v_offset() + offset_y, 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x_scale, 1.0f, 0, 0, width, height); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alpha != 255) { 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(SkColorSetARGB(alpha, 255, 255, 255)); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setXfermodeMode(SkXfermode::kDstIn_Mode); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.DrawRect(gfx::Rect(0, 0, width, height), paint); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // White highlight on hover. 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state == views::CustomButton::STATE_HOVERED) 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas.FillRect(GetLocalBounds(), SkColorSetARGB(64, 255, 255, 255)); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::ImageSkiaOperations::CreateMaskedImage( 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia(canvas.ExtractImageRep()), *mask); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia NewTabButton::GetImageForState( 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::CustomButton::ButtonState state, 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor) const { 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int overlay_id = state == views::CustomButton::STATE_PRESSED ? 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_NEWTAB_BUTTON_P : IDR_NEWTAB_BUTTON; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* overlay = GetThemeProvider()->GetImageSkiaNamed(overlay_id); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Canvas canvas( 52068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Size(overlay->width(), overlay->height()), 52168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ui::GetImageScale(scale_factor), 52268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) false); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.DrawImageInt(GetBackgroundImage(state, scale_factor), 0, 0); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the button border with a slight alpha. 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kNativeFrameOverlayAlpha = 178; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kOpaqueFrameOverlayAlpha = 230; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8 alpha = ShouldUseNativeFrame() ? 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNativeFrameOverlayAlpha : kOpaqueFrameOverlayAlpha; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas.DrawImageInt(*overlay, 0, 0, alpha); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::ImageSkia(canvas.ExtractImageRep()); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::ImageSkia NewTabButton::GetImageForScale( 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ScaleFactor scale_factor) const { 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!hover_animation_->is_animating()) 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetImageForState(state(), scale_factor); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::ImageSkiaOperations::CreateBlendedImage( 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetImageForState(views::CustomButton::STATE_NORMAL, scale_factor), 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetImageForState(views::CustomButton::STATE_HOVERED, scale_factor), 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hover_animation_->GetCurrentValue()); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip::RemoveTabDelegate 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AnimationDelegate used when removing a tab. Does the necessary cleanup when 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// done. 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TabStrip::RemoveTabDelegate 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public views::BoundsAnimator::OwnedAnimationDelegate { 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RemoveTabDelegate(TabStrip* tab_strip, Tab* tab); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; 556d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CompleteRemove(); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the animation completes, we send the Container a message to simulate 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a mouse moved event at the current mouse position. This tickles the Tab 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the mouse is currently over to show the "hot" state of the close button. 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void HighlightCloseButton(); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStrip* tabstrip_; 5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab_; 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStrip::RemoveTabDelegate::RemoveTabDelegate(TabStrip* tab_strip, 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab) 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : tabstrip_(tab_strip), 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_(tab) { 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabDelegate::AnimationEnded( 579d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation) { 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompleteRemove(); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabDelegate::AnimationCanceled( 584d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::Animation* animation) { 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompleteRemove(); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabDelegate::CompleteRemove() { 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(tab_->closing()); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabstrip_->RemoveAndDeleteTab(tab_); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HighlightCloseButton(); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabDelegate::HighlightCloseButton() { 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabstrip_->IsDragSessionActive() || 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !tabstrip_->ShouldHighlightCloseButtonAfterRemove()) { 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function is not required (and indeed may crash!) for removes 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spawned by non-mouse closes and drag-detaches. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget* widget = tabstrip_->GetWidget(); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This can be null during shutdown. See http://crbug.com/42737. 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!widget) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) widget->SynthesizeMouseMoveEvent(); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip, public: 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char TabStrip::kViewClassName[] = "TabStrip"; 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int TabStrip::kMiniToNonMiniGap = 3; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStrip::TabStrip(TabStripController* controller) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : controller_(controller), 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_(NULL), 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_unselected_width_(Tab::GetStandardSize().width()), 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_selected_width_(Tab::GetStandardSize().width()), 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_(-1), 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_tab_close_(false), 626d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) animation_container_(new gfx::AnimationContainer()), 627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bounds_animator_(this), 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_type_(TAB_STRIP_LAYOUT_SHRINK), 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) adjust_layout_(false), 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reset_to_shrink_on_exit_(false), 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mouse_move_count_(0), 6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) immersive_style_(false) { 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStrip::~TabStrip() { 6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(TabStripObserver, observers_, 6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripDeleted(this)); 6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The animations may reference the tabs. Shut down the animation before we 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delete the tabs. 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAnimating(false); 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyDragController(); 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure we unhook ourselves as a message loop observer so that we don't 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // crash in the case where the user closes the window after closing a tab 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but before moving the mouse. 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveMessageLoopObserver(); 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The children (tabs) may callback to us from their destructor. Delete them 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that if they call back we aren't in a weird state. 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveAllChildViews(true); 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::AddObserver(TabStripObserver* observer) { 6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::RemoveObserver(TabStripObserver* observer) { 6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetLayoutType(TabStripLayoutType layout_type, 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool adjust_layout) { 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) adjust_layout_ = adjust_layout; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (layout_type == layout_type_) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int active_index = controller_->GetActiveIndex(); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int active_center = 0; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active_index != -1) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_center = ideal_bounds(active_index).x() + 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(active_index).width() / 2; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) layout_type_ = layout_type; 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit(false); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When transitioning to stacked try to keep the active tab centered. 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get() && active_index != -1) { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetActiveTabLocation( 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_center - ideal_bounds(active_index).width() / 2); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect TabStrip::GetNewTabButtonBounds() { 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return newtab_button_->bounds(); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::SizeTabButtonToTopOfTabStrip() { 6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Extend the button to the screen edge in maximized and immersive fullscreen. 6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Widget* widget = GetWidget(); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return browser_defaults::kSizeTabButtonToTopOfTabStrip || 6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (widget && (widget->IsMaximized() || widget->IsFullscreen())); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartHighlight(int model_index) { 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(model_index)->StartPulse(); 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StopAllHighlighting() { 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(i)->StopPulse(); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::AddTabAt(int model_index, 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TabRendererData& data, 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_active) { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop dragging when a new tab is added and dragging a window. Doing 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // otherwise results in a confusing state if the user attempts to reattach. We 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // could allow this and make TabDragController update itself during the add, 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but this comes up infrequently enough that it's not work the complexity. 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drag_controller_.get() && !drag_controller_->is_mutating() && 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_->is_dragging_window()) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDrag(END_DRAG_COMPLETE); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = CreateTab(); 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->SetData(data); 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateTabsClosingMap(model_index, 1); 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_.Add(tab, model_index); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(tab); 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBoundsForMiniTabs(NULL); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int add_types = 0; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data.mini) 7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) add_types |= StackedTabStripLayout::kAddTypeMini; 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_active) 7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) add_types |= StackedTabStripLayout::kAddTypeActive; 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->AddTab(model_index, add_types, GetStartXForNormalTabs()); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't animate the first tab, it looks weird, and don't animate anything 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if the containing window isn't visible yet. 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count() > 1 && GetWidget() && GetWidget()->IsVisible()) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartInsertTabAnimation(model_index); 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoLayout(); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(TabStripObserver, observers_, 7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripAddedTabAt(this, model_index)); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::MoveTab(int from_model_index, 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int to_model_index, 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TabRendererData& data) { 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(tabs_.view_size(), 0); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* last_tab = tab_at(tab_count() - 1); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(from_model_index)->SetData(data); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_.MoveViewOnly(from_model_index, to_model_index); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_count = 0; 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBoundsForMiniTabs(&mini_count); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->MoveTab( 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from_model_index, to_model_index, controller_->GetActiveIndex(), 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetStartXForNormalTabs(), mini_count); 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_.Move(from_model_index, to_model_index); 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartMoveTabAnimation(); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TabDragController::IsAttachedTo(this) && 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (last_tab != tab_at(tab_count() - 1) || last_tab->dragging())) { 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(false); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(TabStripObserver, observers_, 7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripMovedTab(this, from_model_index, to_model_index)); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabAt(int model_index) { 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(model_index); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->set_closing(true); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_x = tabs_.ideal_bounds(model_index).x(); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We still need to paint the tab until we actually remove it. Put it in 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tabs_closing_map_ so we can find it. 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveTabFromViewModel(model_index); 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->RemoveTab(model_index, GenerateIdealBoundsForMiniTabs(NULL), 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_x); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleRemoveTabAnimation(tab); 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (in_tab_close_ && model_index != GetModelCount()) { 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartMouseInitiatedRemoveTabAnimation(model_index); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartRemoveTabAnimation(model_index); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(TabStripObserver, observers_, 7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TabStripRemovedTabAt(this, model_index)); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetTabData(int model_index, const TabRendererData& data) { 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(model_index); 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mini_state_changed = tab->data().mini != data.mini; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->SetData(data); 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mini_state_changed) { 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_tab_count = 0; 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_x = GenerateIdealBoundsForMiniTabs(&mini_tab_count); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetXAndMiniCount(start_x, mini_tab_count); 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetWidget() && GetWidget()->IsVisible()) 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartMiniTabAnimation(); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoLayout(); 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::PrepareForCloseAt(int model_index, CloseTabSource source) { 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!in_tab_close_ && IsAnimating()) { 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel any current animations. We do this as remove uses the current 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ideal bounds and we need to know ideal bounds is in a good state. 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAnimating(true); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetWidget()) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int model_count = GetModelCount(); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model_index + 1 != model_count && model_count > 1) { 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The user is about to close a tab other than the last tab. Set 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // available_width_for_tabs_ so that if we do a layout we don't position a 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tab past the end of the second to last tab. We do this so that as the 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // user closes tabs with the mouse a tab continues to fall under the mouse. 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* last_tab = tab_at(model_count - 1); 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab_being_removed = tab_at(model_index); 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_ = last_tab->x() + last_tab->width() - 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_being_removed->width() - tab_h_offset(); 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model_index == 0 && tab_being_removed->data().mini && 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !tab_at(1)->data().mini) { 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_ -= kMiniToNonMiniGap; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_tab_close_ = true; 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resize_layout_timer_.Stop(); 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source == CLOSE_TAB_FROM_TOUCH) { 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartResizeLayoutTabsFromTouchTimer(); 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMessageLoopObserver(); 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::SetSelection(const ui::ListSelectionModel& old_selection, 8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::ListSelectionModel& new_selection) { 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetActiveIndex(new_selection.active()); 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only start an animation if we need to. Otherwise clicking on an 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unselected tab and dragging won't work because dragging is only allowed 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if not animating. 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!views::ViewModelUtils::IsAtIdealBounds(tabs_)) 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have "tiny tabs" if the tabs are so tiny that the unselected ones are 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a different size to the selected ones. 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool tiny_tabs = current_unselected_width_ != current_selected_width_; 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsAnimating() && (!in_tab_close_ || tiny_tabs)) { 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoLayout(); 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ui::ListSelectionModel::SelectedIndices no_longer_selected = 8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>( 8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) old_selection.selected_indices(), 8743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) new_selection.selected_indices()); 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < no_longer_selected.size(); ++i) 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(no_longer_selected[i])->StopMiniTabTitleAnimation(); 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::TabTitleChangedNotLoading(int model_index) { 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(model_index); 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->data().mini && !tab->IsActive()) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->StartMiniTabTitleAnimation(); 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab* TabStrip::tab_at(int index) const { 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<Tab*>(tabs_.view_at(index)); 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TabStrip::GetModelIndexOfTab(const Tab* tab) const { 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tabs_.GetIndexOfView(tab); 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::GetModelCount() const { 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return controller_->GetCount(); 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsValidModelIndex(int model_index) const { 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return controller_->IsValidIndex(model_index); 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Tab* TabStrip::CreateTabForDragging() { 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = new Tab(NULL); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the dragged tab shares our theme provider. We need to explicitly 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do this as during dragging there isn't a theme provider. 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->set_theme_provider(GetThemeProvider()); 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab; 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsDragSessionActive() const { 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return drag_controller_.get() != NULL; 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsActiveDropTarget() const { 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->dragging()) 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsTabStripEditable() const { 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !IsDragSessionActive() && !IsActiveDropTarget(); 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsTabStripCloseable() const { 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !IsDragSessionActive(); 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::UpdateLoadingAnimations() { 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->UpdateLoadingAnimations(); 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) { 935f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return IsRectInWindowCaption(gfx::Rect(point, gfx::Size(1, 1))); 936f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 937f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 938f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool TabStrip::IsRectInWindowCaption(const gfx::Rect& rect) { 939f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::View* v = GetEventHandlerForRect(rect); 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no control at this location, claim the hit was in the title 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bar to get a move action. 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (v == this) 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 946f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Check to see if the rect intersects the non-button parts of the new tab 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button. The button has a non-rectangular shape, so if it's not in the 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visual portions of the button we treat it as a click to the caption. 949f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::RectF rect_in_newtab_coords_f(rect); 950f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) View::ConvertRectToTarget(this, newtab_button_, &rect_in_newtab_coords_f); 951f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Rect rect_in_newtab_coords = gfx::ToEnclosingRect( 952f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) rect_in_newtab_coords_f); 953f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (newtab_button_->GetLocalBounds().Intersects(rect_in_newtab_coords) && 954f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !newtab_button_->HitTestRect(rect_in_newtab_coords)) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All other regions, including the new Tab button, should be considered part 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the containing Window's client area so that regular events can be 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // processed for them. 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(i)->set_background_offset(offset); 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->set_background_offset(offset); 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* TabStrip::newtab_button() { 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return newtab_button_; 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::SetImmersiveStyle(bool enable) { 9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (immersive_style_ == enable) 9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) immersive_style_ = enable; 9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::IsAnimating() const { 9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return bounds_animator_.IsAnimating(); 9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::StopAnimating(bool layout) { 9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!IsAnimating()) 9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bounds_animator_.Cancel(); 9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (layout) 9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoLayout(); 9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 993a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void TabStrip::FileSupported(const GURL& url, bool supported) { 994a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (drop_info_.get() && drop_info_->url == url) 995a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) drop_info_->file_supported = supported; 996a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 997a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const ui::ListSelectionModel& TabStrip::GetSelectionModel() { 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return controller_->GetSelectionModel(); 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::SupportsMultipleSelection() { 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO: currently only allow single selection in touch layout mode. 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return touch_layout_.get() == NULL; 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::SelectTab(Tab* tab) { 10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidModelIndex(model_index)) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->SelectTab(model_index); 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::ExtendSelectionTo(Tab* tab) { 10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidModelIndex(model_index)) 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->ExtendSelectionTo(model_index); 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::ToggleSelected(Tab* tab) { 10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidModelIndex(model_index)) 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->ToggleSelected(model_index); 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::AddSelectionFromAnchorTo(Tab* tab) { 10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidModelIndex(model_index)) 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->AddSelectionFromAnchorTo(model_index); 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::CloseTab(Tab* tab, CloseTabSource source) { 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->closing()) { 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the tab is already closing, close the next tab. We do this so that the 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // user can rapidly close tabs by clicking the close button and not have 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the animations interfere with that. 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TabsClosingMap::const_iterator i(tabs_closing_map_.begin()); 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != tabs_closing_map_.end(); ++i) { 10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<Tab*>::const_iterator j = 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(i->second.begin(), i->second.end(), tab); 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (j != i->second.end()) { 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->first + 1 < GetModelCount()) 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->CloseTab(i->first + 1, source); 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we get here, it means a tab has been marked as closing but isn't in 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the set of known closing tabs. 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidModelIndex(model_index)) 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->CloseTab(model_index, source); 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void TabStrip::ShowContextMenuForTab(Tab* tab, 10577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const gfx::Point& p, 10587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ui::MenuSourceType source_type) { 10597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) controller_->ShowContextMenuForTab(tab, p, source_type); 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::IsActiveTab(const Tab* tab) const { 10632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsValidModelIndex(model_index) && 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->IsActiveTab(model_index); 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::IsTabSelected(const Tab* tab) const { 10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsValidModelIndex(model_index) && 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->IsTabSelected(model_index); 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::IsTabPinned(const Tab* tab) const { 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->closing()) 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsValidModelIndex(model_index) && 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->IsTabPinned(model_index); 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::MaybeStartDrag( 10842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab, 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::LocatedEvent& event, 10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::ListSelectionModel& original_selection) { 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't accidentally start any drag operations during animations if the 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse is down... during an animation tabs are being resized automatically, 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so the View system can misinterpret this easily if the mouse is down that 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the user is dragging. 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsAnimating() || tab->closing() || 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->HasAvailableDragActions() == 0) { 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 109590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 109690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Do not do any dragging of tabs when using the super short immersive style. 109790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (IsImmersiveStyle()) 109890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 109990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int model_index = GetModelIndexOfTab(tab); 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidModelIndex(model_index)) { 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(false); 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<Tab*> tabs; 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size_to_selected = 0; 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = tab->GetMirroredXInView(event.x()); 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = event.y(); 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Build the set of selected tabs to drag and calculate the offset from the 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // first selected tab. 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* other_tab = tab_at(i); 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsTabSelected(other_tab)) { 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs.push_back(other_tab); 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (other_tab == tab) { 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_to_selected = GetSizeNeededForTabs(tabs); 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x = size_to_selected - tab->width() + x; 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!tabs.empty()); 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(std::find(tabs.begin(), tabs.end(), tab) != tabs.end()); 11232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::ListSelectionModel selection_model; 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!original_selection.IsSelected(model_index)) 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selection_model.Copy(original_selection); 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Delete the existing DragController before creating a new one. We do this as 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // creating the DragController remembers the WebContents delegates and we need 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to make sure the existing DragController isn't still a delegate. 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_.reset(); 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabDragController::DetachBehavior detach_behavior = 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabDragController::DETACHABLE; 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabDragController::MoveBehavior move_behavior = 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabDragController::REORDER; 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use MOVE_VISIBILE_TABS in the following conditions: 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // . Mouse event generated from touch and the left button is down (the right 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button corresponds to a long press, which we want to reorder). 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // . Gesture begin and control key isn't down. 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // . Real mouse event and control is down. This is mostly for testing. 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(event.type() == ui::ET_MOUSE_PRESSED || 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event.type() == ui::ET_GESTURE_BEGIN); 11412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (touch_layout_.get() && 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((event.type() == ui::ET_MOUSE_PRESSED && 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (((event.flags() & ui::EF_FROM_TOUCH) && 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<const ui::MouseEvent&>(event).IsLeftMouseButton()) || 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!(event.flags() & ui::EF_FROM_TOUCH) && 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<const ui::MouseEvent&>(event).IsControlDown()))) || 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (event.type() == ui::ET_GESTURE_BEGIN && !event.IsControlDown()))) { 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) move_behavior = TabDragController::MOVE_VISIBILE_TABS; 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Widget* widget = GetWidget(); 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 11532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It doesn't make sense to drag tabs out on Win8's single window Metro mode. 11542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (win8::IsSingleWindowMetroMode()) 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) detach_behavior = TabDragController::NOT_DETACHABLE; 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gestures don't automatically do a capture. We don't allow multiple drags at 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the same time, so we explicitly capture. 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.type() == ui::ET_GESTURE_BEGIN) 11602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) widget->SetCapture(this); 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_.reset(new TabDragController); 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_->Init( 11632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, tab, tabs, gfx::Point(x, y), event.x(), selection_model, 11642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) detach_behavior, move_behavior, EventSourceFromEvent(event)); 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::ContinueDrag(views::View* view, const ui::LocatedEvent& event) { 11682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (drag_controller_.get() && 11692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) drag_controller_->event_source() == EventSourceFromEvent(event)) { 11702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point screen_location(event.location()); 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToScreen(view, &screen_location); 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_->Drag(screen_location); 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::EndDrag(EndDragReason reason) { 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!drag_controller_.get()) 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool started_drag = drag_controller_->started_drag(); 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_->EndDrag(reason); 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return started_drag; 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Tab* TabStrip::GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) { 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point local_point = tab_in_tab_coordinates; 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToTarget(tab, this, &local_point); 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* view = GetEventHandlerForPoint(local_point); 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!view) 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; // No tab contains the point. 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk up the view hierarchy until we find a tab, or the TabStrip. 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (view && view != this && view->id() != VIEW_ID_TAB) 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) view = view->parent(); 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return view && view->id() == VIEW_ID_TAB ? static_cast<Tab*>(view) : NULL; 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnMouseEventInTab(views::View* source, 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::MouseEvent& event) { 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateLayoutTypeFromMouseEvent(source, event); 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::ShouldPaintTab(const Tab* tab, gfx::Rect* clip) { 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only touch layout needs to restrict the clip. 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(touch_layout_.get() || IsStackingDraggedTabs())) 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int index = GetModelIndexOfTab(tab); 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index == -1) 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Tab is closing, paint it all. 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int active_index = IsStackingDraggedTabs() ? 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->GetActiveIndex() : touch_layout_->active_index(); 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active_index == tab_count()) 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_index--; 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index < active_index) { 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_at(index)->x() == tab_at(index + 1)->x()) 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_at(index)->x() > tab_at(index + 1)->x()) 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Can happen during dragging. 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clip->SetRect(0, 0, tab_at(index + 1)->x() - tab_at(index)->x() + 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stacked_tab_left_clip(), 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(index)->height()); 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (index > active_index && index > 0) { 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& tab_bounds(tab_at(index)->bounds()); 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& previous_tab_bounds(tab_at(index - 1)->bounds()); 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_bounds.x() == previous_tab_bounds.x()) 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_bounds.x() < previous_tab_bounds.x()) 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Can happen during dragging. 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (previous_tab_bounds.right() + tab_h_offset() != tab_bounds.x()) { 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = previous_tab_bounds.right() - tab_bounds.x() - 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stacked_tab_right_clip(); 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clip->SetRect(x, 0, tab_bounds.width() - x, tab_bounds.height()); 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStrip::IsImmersiveStyle() const { 12472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return immersive_style_; 12482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::MouseMovedOutOfHost() { 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResizeLayoutTabs(); 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reset_to_shrink_on_exit_) { 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reset_to_shrink_on_exit_ = false; 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLayoutType(TAB_STRIP_LAYOUT_SHRINK, true); 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->LayoutTypeMaybeChanged(); 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip, views::View overrides: 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::Layout() { 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only do a layout if our size changed. 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_layout_size_ == size()) 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsDragSessionActive()) 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoLayout(); 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::PaintChildren(gfx::Canvas* canvas) { 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The view order doesn't match the paint order (tabs_ contains the tab 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ordering). Additionally we need to paint the tabs that are closing in 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |tabs_closing_map_|. 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* active_tab = NULL; 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<Tab*> tabs_dragging; 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<Tab*> selected_tabs; 12782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int selected_tab_count = 0; 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_dragging = false; 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int active_tab_index = -1; 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since |touch_layout_| is created based on number of tabs and width we use 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the ideal state to determine if we should paint stacked. This minimizes 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // painting changes as we switch between the two. 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool stacking = (layout_type_ == TAB_STRIP_LAYOUT_STACKED) || 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsStackingDraggedTabs(); 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const chrome::HostDesktopType host_desktop_type = 12882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView()); 12892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int inactive_tab_alpha = 12902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH ? 12912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kInactiveTabAndNewTabButtonAlphaAsh : 12922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kInactiveTabAndNewTabButtonAlpha; 12932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 12942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (inactive_tab_alpha < 255) 12952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->SaveLayerAlpha(inactive_tab_alpha); 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintClosingTabs(canvas, tab_count()); 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = tab_count() - 1; i >= 0; --i) { 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 13012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tab->IsSelected()) 13022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selected_tab_count++; 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->dragging() && !stacking) { 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_dragging = true; 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab->IsActive()) { 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab = tab; 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab_index = i; 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_dragging.push_back(tab); 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!tab->IsActive()) { 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tab->IsSelected()) { 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!stacking) 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->Paint(canvas); 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_tabs.push_back(tab); 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab = tab; 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab_index = i; 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintClosingTabs(canvas, i); 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw from the left and then the right if we're in touch mode. 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stacking && active_tab_index >= 0) { 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < active_tab_index; ++i) { 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->Paint(canvas); 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = tab_count() - 1; i > active_tab_index; --i) { 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->Paint(canvas); 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (inactive_tab_alpha < 255) 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Restore(); 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetWidget()->ShouldUseNativeFrame()) { 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure non-active tabs are somewhat transparent. 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkPaint paint; 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there are multiple tabs selected, fade non-selected tabs more to make 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the selected tabs more noticable. 13452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int alpha = selected_tab_count > 1 ? 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNativeFrameInactiveTabAlphaMultiSelection : 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNativeFrameInactiveTabAlpha; 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setColor(SkColorSetARGB(alpha, 255, 255, 255)); 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setXfermodeMode(SkXfermode::kDstIn_Mode); 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The tabstrip area overlaps the toolbar area by 2 px. 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawRect(gfx::Rect(0, 0, width(), height() - 2), paint); 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now selected but not active. We don't want these dimmed if using native 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // frame, so they're painted after initial pass. 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < selected_tabs.size(); ++i) 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) selected_tabs[i]->Paint(canvas); 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Next comes the active tab. 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active_tab && !is_dragging) 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab->Paint(canvas); 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Paint the New Tab button. 13652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (inactive_tab_alpha < 255) 13662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) canvas->SaveLayerAlpha(inactive_tab_alpha); 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->Paint(canvas); 13682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (inactive_tab_alpha < 255) 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->Restore(); 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // And the dragged tabs. 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs_dragging.size(); ++i) 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_dragging[i]->Paint(canvas); 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the active tab is being dragged, it goes last. 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active_tab && is_dragging) 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab->Paint(canvas); 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1380b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char* TabStrip::GetClassName() const { 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kViewClassName; 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size TabStrip::GetPreferredSize() { 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For stacked tabs the minimum size is calculated as the size needed to 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handle showing any number of tabs. Otherwise report the minimum width as 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the size required for a single selected tab plus the new tab button. Don't 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // base it on the actual number of tabs because it's undesirable to have the 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // minimum window size change when a new tab is opened. 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int needed_width; 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get() || adjust_layout_) { 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) needed_width = Tab::GetTouchWidth() + 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (2 * kStackedPadding * kMaxStackedCount); 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) needed_width = Tab::GetMinimumSelectedSize().width(); 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) needed_width += new_tab_button_width(); 13982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (immersive_style_) 13992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Size(needed_width, Tab::GetImmersiveHeight()); 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Size(needed_width, Tab::GetMinimumUnselectedSize().height()); 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnDragEntered(const DropTargetEvent& event) { 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Force animations to stop, otherwise it makes the index calculation tricky. 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAnimating(true); 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateDropIndex(event); 1408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GURL url; 1410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 title; 1411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Check whether the event data includes supported drop data. 141381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) if (event.data().GetURLAndTitle( 141481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) ui::OSExchangeData::CONVERT_FILENAMES, &url, &title) && 141581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) url.is_valid()) { 1416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) drop_info_->url = url; 1417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // For file:// URLs, kick off a MIME type request in case they're dropped. 1419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (url.SchemeIsFile()) 1420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) controller()->CheckFileSupported(url); 1421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::OnDragUpdated(const DropTargetEvent& event) { 1425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Update the drop index even if the file is unsupported, to allow 1426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // dragging a file to the contents of another tab. 14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateDropIndex(event); 1428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!drop_info_->file_supported) 1430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return ui::DragDropTypes::DRAG_NONE; 1431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDropEffect(event); 14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnDragExited() { 14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(-1, false); 14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::OnPerformDrop(const DropTargetEvent& event) { 14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!drop_info_.get()) 14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::DragDropTypes::DRAG_NONE; 14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int drop_index = drop_info_->drop_index; 14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool drop_before = drop_info_->drop_before; 1445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const bool file_supported = drop_info_->file_supported; 14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the drop indicator. 14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(-1, false); 14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Do nothing if the file was unsupported or the URL is invalid. The URL may 1451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // have been changed after |drop_info_| was created. 14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL url; 1453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 title; 1454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!file_supported || 145581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) !event.data().GetURLAndTitle( 145681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) ui::OSExchangeData::CONVERT_FILENAMES, &url, &title) || 145781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles) !url.is_valid()) 14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::DragDropTypes::DRAG_NONE; 14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller()->PerformDrop(drop_before, drop_index, url); 14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDropEffect(event); 14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::GetAccessibleState(ui::AccessibleViewState* state) { 14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST; 14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)views::View* TabStrip::GetEventHandlerForRect(const gfx::Rect& rect) { 1470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!views::UsePointBasedTargeting(rect)) 1471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return View::GetEventHandlerForRect(rect); 1472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Point point(rect.CenterPoint()); 1473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!touch_layout_.get()) { 14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return any view that isn't a Tab or this TabStrip immediately. We don't 14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // want to interfere. 1477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) views::View* v = View::GetEventHandlerForRect(rect); 1478b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName)) 14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return v; 14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* tab = FindTabHitByPoint(point); 1482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (tab) 1483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return tab; 14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newtab_button_->visible()) { 14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* view = 14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToViewAndGetEventHandler(this, newtab_button_, point); 14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view) 14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return view; 14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = FindTabForEvent(point); 14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab) 14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ConvertPointToViewAndGetEventHandler(this, tab, point); 14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this; 14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::View* TabStrip::GetTooltipHandlerForPoint(const gfx::Point& point) { 1499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!HitTestPoint(point)) 1500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 1501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!touch_layout_.get()) { 1503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Return any view that isn't a Tab or this TabStrip immediately. We don't 1504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // want to interfere. 1505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* v = View::GetTooltipHandlerForPoint(point); 1506b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName)) 1507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return v; 1508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* tab = FindTabHitByPoint(point); 1510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (tab) 1511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return tab; 1512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 1513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (newtab_button_->visible()) { 1514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) views::View* view = 1515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ConvertPointToViewAndGetTooltipHandler(this, newtab_button_, point); 1516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (view) 1517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return view; 1518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Tab* tab = FindTabForEvent(point); 1520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (tab) 1521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ConvertPointToViewAndGetTooltipHandler(this, tab, point); 1522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return this; 1524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 15262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 15272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TabStrip::GetImmersiveHeight() { 15282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return Tab::GetImmersiveHeight(); 15292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 15302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::GetMiniTabCount() const { 15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_count = 0; 15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (mini_count < tab_count() && tab_at(mini_count)->data().mini) 15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mini_count++; 15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mini_count; 15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip, views::ButtonListener implementation: 15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::ButtonPressed(views::Button* sender, const ui::Event& event) { 15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sender == newtab_button_) { 15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RecordAction(UserMetricsAction("NewTab_Button")); 15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_BUTTON, 15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel::NEW_TAB_ENUM_COUNT); 1546f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (event.IsMouseEvent()) { 1547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const ui::MouseEvent& mouse = static_cast<const ui::MouseEvent&>(event); 1548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mouse.IsOnlyMiddleMouseButton()) { 1549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::string16 clipboard_text = GetClipboardText(); 1550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!clipboard_text.empty()) 1551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) controller()->CreateNewTabWithLocation(clipboard_text); 1552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 1553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 1554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 1555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller()->CreateNewTab(); 1557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (event.type() == ui::ET_GESTURE_TAP) 1558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::RecordGestureAction(TouchUMA::GESTURE_NEWTAB_TAP); 15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip, protected: 15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Overridden to support automation. See automation_proxy_uitest.cc. 15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const views::View* TabStrip::GetViewByID(int view_id) const { 15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count() > 0) { 15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (view_id == VIEW_ID_TAB_LAST) { 15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab_at(tab_count() - 1); 15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { 15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = view_id - VIEW_ID_TAB_0; 15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index >= 0 && index < tab_count()) { 15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab_at(index); 15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return View::GetViewByID(view_id); 15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::OnMousePressed(const ui::MouseEvent& event) { 15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateLayoutTypeFromMouseEvent(this, event); 15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't return true here, else clicking in an empty area won't drag the 15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // window. 15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::OnMouseDragged(const ui::MouseEvent& event) { 15912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ContinueDrag(this, event); 15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnMouseReleased(const ui::MouseEvent& event) { 15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDrag(END_DRAG_COMPLETE); 15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateLayoutTypeFromMouseEvent(this, event); 15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnMouseCaptureLost() { 16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDrag(END_DRAG_CAPTURE_LOST); 16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnMouseMoved(const ui::MouseEvent& event) { 16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateLayoutTypeFromMouseEvent(this, event); 16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OnMouseEntered(const ui::MouseEvent& event) { 16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit(true); 16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::OnGestureEvent(ui::GestureEvent* event) { 16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit(false); 16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event->type()) { 16151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_GESTURE_SCROLL_END: 16161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case ui::ET_SCROLL_FLING_START: 1617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case ui::ET_GESTURE_END: 16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDrag(END_DRAG_COMPLETE); 16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (adjust_layout_) { 16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLayoutType(TAB_STRIP_LAYOUT_STACKED, true); 16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->LayoutTypeMaybeChanged(); 16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_GESTURE_LONG_PRESS: 16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drag_controller_.get()) 16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_->SetMoveBehavior(TabDragController::REORDER); 16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case ui::ET_GESTURE_LONG_TAP: { 16312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EndDrag(END_DRAG_CANCEL); 16322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point local_point = event->location(); 16332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = FindTabForEvent(local_point); 16342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tab) { 16352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ConvertPointToScreen(this, &local_point); 16367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ShowContextMenuForTab(tab, local_point, ui::MENU_SOURCE_TOUCH); 16372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 16382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 16392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 16402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_GESTURE_SCROLL_UPDATE: 16422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ContinueDrag(this, *event); 16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_GESTURE_BEGIN: 16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDrag(END_DRAG_CANCEL); 16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case ui::ET_GESTURE_TAP: { 1650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int active_index = controller_->GetActiveIndex(); 1651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_NE(-1, active_index); 1652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Tab* active_tab = tab_at(active_index); 1653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::GestureActionType action = TouchUMA::GESTURE_TABNOSWITCH_TAP; 1654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (active_tab->tab_activated_with_last_gesture_begin()) 1655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch action = TouchUMA::GESTURE_TABSWITCH_TAP; 1656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::RecordGestureAction(action); 1657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 1658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->SetHandled(); 16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip, private: 16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::Init() { 16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_id(VIEW_ID_TAB_STRIP); 16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // So we get enter/exit on children to switch layout type. 16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_notify_enter_exit_on_child(true); 16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_bounds_.SetRect(0, 16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_asset_width(), 16762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) newtab_button_asset_height() + 16772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) newtab_button_v_offset()); 16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_ = new NewTabButton(this, this); 16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetTooltipText( 16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB)); 16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetAccessibleName( 16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB)); 16832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, 16842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::ImageButton::ALIGN_BOTTOM); 16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(newtab_button_); 16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drop_indicator_width == 0) { 16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Direction doesn't matter, both images are the same size. 16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia* drop_image = GetDropArrowImage(true); 16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_indicator_width = drop_image->width(); 16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_indicator_height = drop_image->height(); 16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Tab* TabStrip::CreateTab() { 16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = new Tab(this); 16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->set_animation_container(animation_container_.get()); 16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab; 16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartInsertTabAnimation(int model_index) { 17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The TabStrip can now use its entire width to lay out Tabs. 17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_tab_close_ = false; 17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_ = -1; 17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 17088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(model_index); 17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model_index == 0) { 17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->SetBounds(0, ideal_bounds(model_index).y(), 0, 17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(model_index).height()); 17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* last_tab = tab_at(model_index - 1); 17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->SetBounds(last_tab->bounds().right() + tab_h_offset(), 17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(model_index).y(), 0, 17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(model_index).height()); 17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartMoveTabAnimation() { 17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartRemoveTabAnimation(int model_index) { 17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark the tab as closing. 17335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(model_index); 17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->set_closing(true); 17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveTabFromViewModel(model_index); 17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleRemoveTabAnimation(tab); 17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::ScheduleRemoveTabAnimation(Tab* tab) { 17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start an animation for the tabs. 17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animate the tab being closed to 0x0. 17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect tab_bounds = tab->bounds(); 17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_bounds.set_width(0); 17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.AnimateViewTo(tab, tab_bounds); 17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Register delegate to do cleanup when done, BoundsAnimator takes 17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ownership of RemoveTabDelegate. 17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.SetAnimationDelegate(tab, new RemoveTabDelegate(this, tab), 17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true); 17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't animate the new tab button when dragging tabs. Otherwise it looks 17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // like the new tab button magically appears from beyond the end of the tab 17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // strip. 17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (TabDragController::IsAttachedTo(this)) { 17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.StopAnimatingView(newtab_button_); 17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetBoundsRect(newtab_button_bounds_); 17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::AnimateToIdealBounds() { 17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tab->dragging()) 17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.AnimateViewTo(tab, ideal_bounds(i)); 17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.AnimateViewTo(newtab_button_, newtab_button_bounds_); 17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { 17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return in_tab_close_; 17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::DoLayout() { 17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_layout_size_ = size(); 17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAnimating(false); 17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SwapLayoutIfNecessary(); 17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) 17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetWidth(size().width() - new_tab_button_width()); 17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_); 17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.StopAnimatingView(newtab_button_); 17965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetBoundsRect(newtab_button_bounds_); 17975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::DragActiveTab(const std::vector<int>& initial_positions, 18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta) { 18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(tab_count(), static_cast<int>(initial_positions.size())); 18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!touch_layout_.get()) { 18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StackDraggedTabs(delta); 18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetIdealBoundsFromPositions(initial_positions); 18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->DragActiveTab(delta); 18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoLayout(); 18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetIdealBoundsFromPositions(const std::vector<int>& positions) { 18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (static_cast<size_t>(tab_count()) != positions.size()) 18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect bounds(ideal_bounds(i)); 18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds.set_x(positions[i]); 18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, bounds); 18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StackDraggedTabs(int delta) { 18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!touch_layout_.get()); 18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int active_index = controller_->GetActiveIndex(); 18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(-1, active_index); 18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delta < 0) { 18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Drag the tabs to the left, stacking tabs before the active tab. 18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int adjusted_delta = 18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(ideal_bounds(active_index).x() - 18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStackedPadding * std::min(active_index, kMaxStackedCount), 18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -delta); 18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= active_index; ++i) { 18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int min_x = std::min(i, kMaxStackedCount) * kStackedPadding; 18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds(ideal_bounds(i)); 18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.set_x(std::max(min_x, new_bounds.x() - adjusted_delta)); 18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, new_bounds); 18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool is_active_mini = tab_at(active_index)->data().mini; 18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int active_width = ideal_bounds(active_index).width(); 18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = active_index + 1; i < tab_count(); ++i) { 18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_x = ideal_bounds(active_index).x() + 18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kStackedPadding * std::min(i - active_index, kMaxStackedCount)); 18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds(ideal_bounds(i)); 18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_x = std::max(new_bounds.x() + delta, max_x); 18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_x == max_x && !tab_at(i)->data().mini && !is_active_mini && 18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.width() != active_width) 18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_x += (active_width - new_bounds.width()); 18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.set_x(new_x); 18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, new_bounds); 18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Drag the tabs to the right, stacking tabs after the active tab. 18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int last_tab_width = ideal_bounds(tab_count() - 1).width(); 18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int last_tab_x = width() - new_tab_button_width() - last_tab_width; 18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (active_index == tab_count() - 1 && 18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(tab_count() - 1).x() == last_tab_x) 18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int adjusted_delta = 18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(last_tab_x - 18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStackedPadding * std::min(tab_count() - active_index - 1, 18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxStackedCount) - 18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ideal_bounds(active_index).x(), 18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delta); 18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int last_index = tab_count() - 1, i = last_index; i >= active_index; 18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --i) { 18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_x = last_tab_x - 18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(tab_count() - i - 1, kMaxStackedCount) * kStackedPadding; 18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds(ideal_bounds(i)); 18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_x = std::min(max_x, new_bounds.x() + adjusted_delta); 18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Because of rounding not all tabs are the same width. Adjust the 18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // position to accommodate this, otherwise the stacking is off. 18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_x == max_x && !tab_at(i)->data().mini && 18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.width() != last_tab_width) 18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_x += (last_tab_width - new_bounds.width()); 18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.set_x(new_x); 18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, new_bounds); 18785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = active_index - 1; i >= 0; --i) { 18805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int min_x = ideal_bounds(active_index).x() - 18815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(active_index - i, kMaxStackedCount) * kStackedPadding; 18825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds(ideal_bounds(i)); 18835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.set_x(std::min(min_x, new_bounds.x() + delta)); 18845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, new_bounds); 18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ideal_bounds(tab_count() - 1).right() >= newtab_button_->x()) 18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(false); 18885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_); 18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsStackingDraggedTabs() const { 18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return drag_controller_.get() && drag_controller_->started_drag() && 18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (drag_controller_->move_behavior() == 18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabDragController::MOVE_VISIBILE_TABS); 18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::LayoutDraggedTabsAt(const std::vector<Tab*>& tabs, 19002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* active_tab, 19015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Point& location, 19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool initial_drag) { 19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Immediately hide the new tab button if the last tab is being dragged. 19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_at(tab_count() - 1)->dragging()) 19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(false); 19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<gfx::Rect> bounds; 19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CalculateBoundsForDraggedTabs(tabs, &bounds); 19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(tabs.size(), bounds.size()); 19092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int active_tab_model_index = GetModelIndexOfTab(active_tab); 19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int active_tab_index = static_cast<int>( 19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(tabs.begin(), tabs.end(), active_tab) - tabs.begin()); 19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) { 19132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = tabs[i]; 19145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds = bounds[i]; 19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.Offset(location.x(), location.y()); 19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int consecutive_index = 19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_tab_model_index - (active_tab_index - static_cast<int>(i)); 19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this is the initial layout during a drag and the tabs aren't 19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // consecutive animate the view into position. Do the same if the tab is 19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // already animating (which means we previously caused it to animate). 19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((initial_drag && 19222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetModelIndexOfTab(tabs[i]) != consecutive_index) || 19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.IsAnimating(tabs[i])) { 19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.SetTargetBounds(tabs[i], new_bounds); 19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->SetBoundsRect(new_bounds); 19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::CalculateBoundsForDraggedTabs(const std::vector<Tab*>& tabs, 19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<gfx::Rect>* bounds) { 19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = 0; 19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) { 19352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = tabs[i]; 19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i > 0 && tab->data().mini != tabs[i - 1]->data().mini) 19375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x += kMiniToNonMiniGap; 19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect new_bounds = tab->bounds(); 19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_bounds.set_origin(gfx::Point(x, 0)); 19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds->push_back(new_bounds); 19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x += tab->width() + tab_h_offset(); 19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int TabStrip::GetSizeNeededForTabs(const std::vector<Tab*>& tabs) { 19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = 0; 19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) { 19482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = tabs[i]; 19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width += tab->width(); 19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i > 0 && tab->data().mini != tabs[i - 1]->data().mini) 19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width += kMiniToNonMiniGap; 19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs.size() > 0) 19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) width += tab_h_offset() * static_cast<int>(tabs.size() - 1); 19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return width; 19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveTabFromViewModel(int index) { 19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We still need to paint the tab until we actually remove it. Put it 19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in tabs_closing_map_ so we can find it. 19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_[index].push_back(tab_at(index)); 19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateTabsClosingMap(index + 1, -1); 19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_.Remove(index); 19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::RemoveAndDeleteTab(Tab* tab) { 19672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<Tab> deleter(tab); 19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TabsClosingMap::iterator i(tabs_closing_map_.begin()); 19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != tabs_closing_map_.end(); ++i) { 19702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<Tab*>::iterator j = 19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(i->second.begin(), i->second.end(), tab); 19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (j != i->second.end()) { 19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i->second.erase(j); 19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->second.empty()) 19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_.erase(i); 19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::UpdateTabsClosingMap(int index, int delta) { 19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs_closing_map_.empty()) 19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 19855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delta == -1 && 19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_.find(index - 1) != tabs_closing_map_.end() && 19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_.find(index) != tabs_closing_map_.end()) { 19892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<Tab*>& tabs(tabs_closing_map_[index]); 19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_[index - 1].insert( 19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_[index - 1].end(), tabs.begin(), tabs.end()); 19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabsClosingMap updated_map; 19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TabsClosingMap::iterator i(tabs_closing_map_.begin()); 19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != tabs_closing_map_.end(); ++i) { 19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i->first > index) 19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updated_map[i->first + delta] = i->second; 19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (i->first < index) 19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updated_map[i->first] = i->second; 20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delta > 0 && tabs_closing_map_.find(index) != tabs_closing_map_.end()) 20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updated_map[index + delta] = tabs_closing_map_[index]; 20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs_closing_map_.swap(updated_map); 20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::StartedDraggingTabs(const std::vector<Tab*>& tabs) { 20077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Let the controller know that the user started dragging tabs. 20087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) controller()->OnStartedDraggingTabs(); 20097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide the new tab button immediately if we didn't originate the drag. 20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!drag_controller_.get()) 20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(false); 20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset dragging state of existing tabs. 20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(i)->set_dragging(false); 20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) { 20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs[i]->set_dragging(true); 20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.StopAnimatingView(tabs[i]); 20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Move the dragged tabs to their ideal bounds. 20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets the bounds of the dragged tabs. 20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) { 20302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int tab_data_index = GetModelIndexOfTab(tabs[i]); 20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(-1, tab_data_index); 20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index)); 20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::DraggedTabsDetached() { 20387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Let the controller know that the user is not dragging this tabstrip's tabs 20397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // anymore. 20407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) controller()->OnStoppedDraggingTabs(); 20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(true); 20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::StoppedDraggingTabs(const std::vector<Tab*>& tabs, 20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<int>& initial_positions, 20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool move_only, 20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool completed) { 20487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Let the controller know that the user stopped dragging tabs. 20497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) controller()->OnStoppedDraggingTabs(); 20507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(true); 20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (move_only && touch_layout_.get()) { 20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (completed) { 20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SizeToFit(); 20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetIdealBoundsFromPositions(initial_positions); 20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_first_tab = true; 20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tabs.size(); ++i) 20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StoppedDraggingTab(tabs[i], &is_first_tab); 20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::StoppedDraggingTab(Tab* tab, bool* is_first_tab) { 20652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int tab_data_index = GetModelIndexOfTab(tab); 20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_data_index == -1) { 20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The tab was removed before the drag completed. Don't do anything. 20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*is_first_tab) { 20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *is_first_tab = false; 20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Animate the view back to its correct position. 20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.AnimateViewTo(tab, ideal_bounds(tab_data_index)); 20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Install a delegate to reset the dragging state when done. We have to leave 20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dragging true for the tab otherwise it'll draw beneath the new tab button. 20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.SetAnimationDelegate( 20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab, new ResetDraggingStateDelegate(tab), true); 20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::OwnDragController(TabDragController* controller) { 20872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Typically, ReleaseDragController() and OwnDragController() calls are paired 20882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // via corresponding calls to TabDragController::Detach() and 20892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TabDragController::Attach(). There is one exception to that rule: when a 20902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // drag might start, we create a TabDragController that is owned by the 20912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // potential source tabstrip in MaybeStartDrag(). If a drag actually starts, 20922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // we then call Attach() on the source tabstrip, but since the source tabstrip 20932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // already owns the TabDragController, so we don't need to do anything. 20942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (controller != drag_controller_.get()) 20952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) drag_controller_.reset(controller); 20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::DestroyDragController() { 20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_->SetVisible(true); 21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drag_controller_.reset(); 21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabDragController* TabStrip::ReleaseDragController() { 21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return drag_controller_.release(); 21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::PaintClosingTabs(gfx::Canvas* canvas, int index) { 21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs_closing_map_.find(index) == tabs_closing_map_.end()) 21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<Tab*>& tabs = tabs_closing_map_[index]; 21122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<Tab*>::const_reverse_iterator i(tabs.rbegin()); 21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != tabs.rend(); ++i) { 21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*i)->Paint(canvas); 21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::UpdateLayoutTypeFromMouseEvent(views::View* source, 21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::MouseEvent& event) { 21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetAdjustLayout()) 21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The following code attempts to switch to TAB_STRIP_LAYOUT_SHRINK when the 21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse exits the tabstrip (or the mouse is pressed on a stacked tab) and 21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TAB_STRIP_LAYOUT_STACKED when a touch device is used. This is made 21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // problematic by windows generating mouse move events that do not clearly 21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // indicate the move is the result of a touch device. This assumes a real 21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse is used if |kMouseMoveCountBeforeConsiderReal| mouse move events are 21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // received within the time window |kMouseMoveTimeMS|. At the time we get a 21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mouse press we know whether its from a touch device or not, but we don't 21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // layout then else everything shifts. Instead we wait for the release. 21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(sky): revisit this when touch events are really plumbed through. 21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event.type()) { 21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_PRESSED: 21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_move_count_ = 0; 21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_time_ = base::TimeTicks(); 21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit((event.flags() & ui::EF_FROM_TOUCH) == 0); 21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reset_to_shrink_on_exit_ && touch_layout_.get()) { 21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point tab_strip_point(event.location()); 21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View::ConvertPointToTarget(source, this, &tab_strip_point); 21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = FindTabForEvent(tab_strip_point); 21442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tab && touch_layout_->IsStacked(GetModelIndexOfTab(tab))) { 21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLayoutType(TAB_STRIP_LAYOUT_SHRINK, true); 21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->LayoutTypeMaybeChanged(); 21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_MOVED: { 21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_ASH) 21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ash does not synthesize mouse events from touch events. 21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit(true); 21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point location(event.location()); 21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToTarget(source, this, &location); 21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (location == last_mouse_move_location_) 21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Ignore spurious moves. 21605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_location_ = location; 21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((event.flags() & ui::EF_FROM_TOUCH) == 0 && 21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (event.flags() & ui::EF_IS_SYNTHESIZED) == 0) { 21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((base::TimeTicks::Now() - last_mouse_move_time_).InMilliseconds() < 21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMouseMoveTimeMS) { 21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mouse_move_count_++ == kMouseMoveCountBeforeConsiderReal) 21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetResetToShrinkOnExit(true); 21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_move_count_ = 1; 21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_time_ = base::TimeTicks::Now(); 21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_time_ = base::TimeTicks(); 21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_RELEASED: { 21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point location(event.location()); 21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToTarget(source, this, &location); 21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_location_ = location; 21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_move_count_ = 0; 21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_mouse_move_time_ = base::TimeTicks(); 21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((event.flags() & ui::EF_FROM_TOUCH) == ui::EF_FROM_TOUCH) { 21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetLayoutType(TAB_STRIP_LAYOUT_STACKED, true); 21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller_->LayoutTypeMaybeChanged(); 21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStrip::GetCurrentTabWidths(double* unselected_width, 21972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double* selected_width) const { 21982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *unselected_width = current_unselected_width_; 21992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *selected_width = current_selected_width_; 22002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 22012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::GetDesiredTabWidths(int tab_count, 22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_tab_count, 22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double* unselected_width, 22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double* selected_width) const { 22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(tab_count >= 0 && mini_tab_count >= 0 && mini_tab_count <= tab_count); 22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double min_unselected_width = Tab::GetMinimumUnselectedSize().width(); 22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double min_selected_width = Tab::GetMinimumSelectedSize().width(); 22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *unselected_width = min_unselected_width; 22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *selected_width = min_selected_width; 22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count == 0) { 22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return immediately to avoid divide-by-zero below. 22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Determine how much space we can actually allocate to tabs. 22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int available_width; 22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (available_width_for_tabs_ < 0) { 22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width = width() - new_tab_button_width(); 22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Interesting corner case: if |available_width_for_tabs_| > the result 22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the calculation in the conditional arm above, the strip is in 22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overflow. We can either use the specified width or the true available 22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // width here; the first preserves the consistent "leave the last tab under 22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the user's mouse so they can close many tabs" behavior at the cost of 22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // prolonging the glitchy appearance of the overflow state, while the second 22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // gets us out of overflow as soon as possible but forces the user to move 22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // their mouse for a few tabs' worth of closing. We choose visual 22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // imperfection over behavioral imperfection and select the first option. 22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width = available_width_for_tabs_; 22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mini_tab_count > 0) { 22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width -= mini_tab_count * (Tab::GetMiniWidth() + tab_h_offset()); 22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_count -= mini_tab_count; 22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count == 0) { 22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *selected_width = *unselected_width = Tab::GetStandardSize().width(); 22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Account for gap between the last mini-tab and first non-mini-tab. 22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width -= kMiniToNonMiniGap; 22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the desired tab widths by dividing the available space into equal 22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // portions. Don't let tabs get larger than the "standard width" or smaller 22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // than the minimum width for each type, respectively. 22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int total_offset = tab_h_offset() * (tab_count - 1); 22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double desired_tab_width = std::min((static_cast<double>( 22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width - total_offset) / static_cast<double>(tab_count)), 22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(Tab::GetStandardSize().width())); 22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *unselected_width = std::max(desired_tab_width, min_unselected_width); 22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *selected_width = std::max(desired_tab_width, min_selected_width); 22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When there are multiple tabs, we'll have one selected and some unselected 22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tabs. If the desired width was between the minimum sizes of these types, 22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // try to shrink the tabs with the smaller minimum. For example, if we have 22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5. If 22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected tabs have a minimum width of 4 and unselected tabs have a minimum 22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // width of 1, the above code would set *unselected_width = 2.5, 22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // *selected_width = 4, which results in a total width of 11.5. Instead, we 22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // want to set *unselected_width = 2, *selected_width = 4, for a total width 22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of 10. 22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count > 1) { 22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((min_unselected_width < min_selected_width) && 22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (desired_tab_width < min_selected_width)) { 22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unselected width = (total width - selected width) / (num_tabs - 1) 22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *unselected_width = std::max(static_cast<double>( 22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width - total_offset - min_selected_width) / 22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<double>(tab_count - 1), min_unselected_width); 22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((min_unselected_width > min_selected_width) && 22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (desired_tab_width < min_unselected_width)) { 22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Selected width = (total width - (unselected width * (num_tabs - 1))) 22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *selected_width = std::max(available_width - total_offset - 22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (min_unselected_width * (tab_count - 1)), min_selected_width); 22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::ResizeLayoutTabs() { 22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We've been called back after the TabStrip has been emptied out (probably 22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just prior to the window being destroyed). We need to do nothing here or 22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // else GetTabAt below will crash. 22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_count() == 0) 22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is critically important that this is unhooked here, otherwise we will 22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // keep spying on messages forever. 22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveMessageLoopObserver(); 22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_tab_close_ = false; 22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_ = -1; 22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_tab_count = GetMiniTabCount(); 22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mini_tab_count == tab_count()) { 22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only mini-tabs, we know the tab widths won't have changed (all 22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mini-tabs have the same width), so there is nothing to do. 22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 22995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't try and avoid layout based on tab sizes. If tabs are small enough 23012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // then the width of the active tab may not change, but other widths may 23022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // have. This is particularly important if we've overflowed (all tabs are at 23032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the min). 23042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StartResizeLayoutAnimation(); 23055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::ResizeLayoutTabsFromTouch() { 23085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't resize if the user is interacting with the tabstrip. 23095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!drag_controller_.get()) 23105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResizeLayoutTabs(); 23115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 23125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartResizeLayoutTabsFromTouchTimer(); 23135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartResizeLayoutTabsFromTouchTimer() { 23165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resize_layout_timer_.Stop(); 23175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resize_layout_timer_.Start( 23185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, base::TimeDelta::FromMilliseconds(kTouchResizeLayoutTimeMS), 23195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, &TabStrip::ResizeLayoutTabsFromTouch); 23205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds) { 23235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAnimating(false); 23245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(tab_count(), static_cast<int>(tab_bounds.size())); 23255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 23265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(i)->SetBoundsRect(tab_bounds[i]); 23275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::AddMessageLoopObserver() { 23305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mouse_watcher_.get()) { 23315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_watcher_.reset( 23325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new views::MouseWatcher( 23335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new views::MouseWatcherViewHost( 23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, gfx::Insets(0, 0, kTabStripAnimationVSlop, 0)), 23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this)); 23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_watcher_->Start(); 23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::RemoveMessageLoopObserver() { 23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mouse_watcher_.reset(NULL); 23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect TabStrip::GetDropBounds(int drop_index, 23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool drop_before, 23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* is_beneath) { 23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(drop_index, -1); 23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int center_x; 23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drop_index < tab_count()) { 23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(drop_index); 23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drop_before) 23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center_x = tab->x() - (tab_h_offset() / 2); 23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center_x = tab->x() + (tab->width() / 2); 23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* last_tab = tab_at(drop_index - 1); 23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center_x = last_tab->x() + last_tab->width() + (tab_h_offset() / 2); 23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mirror the center point if necessary. 23615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) center_x = GetMirroredXInView(center_x); 23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Determine the screen bounds. 23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point drop_loc(center_x - drop_indicator_width / 2, 23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -drop_indicator_height); 23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertPointToScreen(this, &drop_loc); 23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect drop_bounds(drop_loc.x(), drop_loc.y(), drop_indicator_width, 23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_indicator_height); 23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the rect doesn't fit on the monitor, push the arrow to the bottom. 237168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Screen* screen = gfx::Screen::GetScreenFor(GetWidget()->GetNativeView()); 237268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::Display display = screen->GetDisplayMatching(drop_bounds); 237368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) *is_beneath = !display.bounds().Contains(drop_bounds); 23745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*is_beneath) 23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_bounds.Offset(0, drop_bounds.height() + height()); 23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return drop_bounds; 23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { 23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the UI layout is right-to-left, we need to mirror the mouse 23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // coordinates since we calculate the drop index based on the 23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // original (and therefore non-mirrored) positions of the tabs. 23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int x = GetMirroredXInView(event.x()); 23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't allow replacing the urls of mini-tabs. 23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = GetMiniTabCount(); i < tab_count(); ++i) { 23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int tab_max_x = tab->x() + tab->width(); 23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int hot_width = tab->width() / kTabEdgeRatioInverse; 23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (x < tab_max_x) { 23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (x < tab->x() + hot_width) 23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(i, true); 23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (x >= tab_max_x - hot_width) 23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(i + 1, true); 23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(i, false); 23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The drop isn't over a tab, add it to the end. 24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDropIndex(tab_count(), true); 24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) { 24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Let the controller know of the index update. 24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller()->OnDropIndexUpdate(tab_data_index, drop_before); 24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_data_index == -1) { 24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drop_info_.get()) 24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_.reset(NULL); 24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (drop_info_.get() && drop_info_->drop_index == tab_data_index && 24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->drop_before == drop_before) { 24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_beneath; 24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect drop_bounds = GetDropBounds(tab_data_index, drop_before, 24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &is_beneath); 24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!drop_info_.get()) { 24252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) drop_info_.reset( 24262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new DropInfo(tab_data_index, drop_before, !is_beneath, GetWidget())); 24275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->drop_index = tab_data_index; 24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->drop_before = drop_before; 24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_beneath == drop_info_->point_down) { 24315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->point_down = !is_beneath; 24325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->arrow_view->SetImage( 24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDropArrowImage(drop_info_->point_down)); 24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reposition the window. Need to show it too as the window is initially 24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hidden. 24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->arrow_window->SetBounds(drop_bounds); 24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_info_->arrow_window->Show(); 24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::GetDropEffect(const ui::DropTargetEvent& event) { 24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int source_ops = event.source_operations(); 24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source_ops & ui::DragDropTypes::DRAG_COPY) 24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::DragDropTypes::DRAG_COPY; 24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source_ops & ui::DragDropTypes::DRAG_LINK) 24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::DragDropTypes::DRAG_LINK; 24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::DragDropTypes::DRAG_MOVE; 24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia* TabStrip::GetDropArrowImage(bool is_down) { 24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_down ? IDR_TAB_DROP_DOWN : IDR_TAB_DROP_UP); 24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStrip::DropInfo ---------------------------------------------------------- 24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TabStrip::DropInfo::DropInfo(int drop_index, 24612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool drop_before, 24622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool point_down, 24632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) views::Widget* context) 24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : drop_index(drop_index), 24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drop_before(drop_before), 2466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) point_down(point_down), 2467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) file_supported(true) { 24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_view = new views::ImageView; 24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_view->SetImage(GetDropArrowImage(point_down)); 24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_window = new views::Widget; 24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.keep_on_top = true; 2474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.accept_events = false; 24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.can_activate = false; 24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.bounds = gfx::Rect(drop_indicator_width, drop_indicator_height); 24782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.context = context->GetNativeView(); 24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_window->Init(params); 24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_window->SetContentsView(arrow_view); 24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStrip::DropInfo::~DropInfo() { 24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close eventually deletes the window, which deletes arrow_view too. 24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arrow_window->Close(); 24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::PrepareForAnimation() { 24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsDragSessionActive() && !TabDragController::IsAttachedTo(this)) { 24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_at(i)->set_dragging(false); 24945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::GenerateIdealBounds() { 24982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int new_tab_y = 0; 24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (touch_layout_.get()) { 25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs_.view_size() == 0) 25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_tab_x = tabs_.ideal_bounds(tabs_.view_size() - 1).right() + 25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_h_offset(); 25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); 25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double unselected, selected; 25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDesiredTabWidths(tab_count(), GetMiniTabCount(), &unselected, &selected); 25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_unselected_width_ = unselected; 25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_selected_width_ = selected; 25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: This currently assumes a tab's height doesn't differ based on 25165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected state or the number of tabs in the strip! 25175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tab_height = Tab::GetStandardSize().height(); 25185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int first_non_mini_index = 0; 25195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double tab_x = GenerateIdealBoundsForMiniTabs(&first_non_mini_index); 25205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = first_non_mini_index; i < tab_count(); ++i) { 25215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab = tab_at(i); 25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!tab->data().mini); 25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double tab_width = tab->IsActive() ? selected : unselected; 25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double end_of_tab = tab_x + tab_width; 25255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rounded_tab_x = Round(tab_x); 25265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds( 25275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i, 25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, 25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_height)); 25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_x = end_of_tab + tab_h_offset(); 25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update bounds of new tab button. 25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_tab_x; 25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && 25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !in_tab_close_) { 25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're shrinking tabs, so we need to anchor the New Tab button to the 25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // right edge of the TabStrip's bounds, rather than the right edge of the 25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // right-most Tab, otherwise it'll bounce when animating. 25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_tab_x = width() - newtab_button_bounds_.width(); 25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_tab_x = Round(tab_x - tab_h_offset()) + newtab_button_h_offset(); 25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); 25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::GenerateIdealBoundsForMiniTabs(int* first_non_mini_index) { 25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int next_x = 0; 25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_width = Tab::GetMiniWidth(); 25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tab_height = Tab::GetStandardSize().height(); 25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; index < tab_count() && tab_at(index)->data().mini; ++index) { 25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(index, 25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect(next_x, 0, mini_width, tab_height)); 25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_x += mini_width + tab_h_offset(); 25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index > 0 && index < tab_count()) 25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_x += kMiniToNonMiniGap; 25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first_non_mini_index) 25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *first_non_mini_index = index; 25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return next_x; 25625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static 25657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint TabStrip::new_tab_button_width() { 25665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return newtab_button_asset_width() + newtab_button_h_offset(); 25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static 25707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint TabStrip::button_v_offset() { 25717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return newtab_button_v_offset(); 25727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 25737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 25747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint TabStrip::tab_area_width() const { 25757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return width() - new_tab_button_width(); 25767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 25777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartResizeLayoutAnimation() { 25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartMiniTabAnimation() { 25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_tab_close_ = false; 25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_width_for_tabs_ = -1; 25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::StartMouseInitiatedRemoveTabAnimation(int model_index) { 25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The user initiated the close. We want to persist the bounds of all the 25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // existing tabs, so we manually shift ideal_bounds then animate. 25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tab* tab_closing = tab_at(model_index); 25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta = tab_closing->width() + tab_h_offset(); 25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the tab being closed is a mini-tab next to a non-mini-tab, be sure to 26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add the extra padding. 26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(model_index + 1, tab_count()); 26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_closing->data().mini && model_index + 1 < tab_count() && 26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !tab_at(model_index + 1)->data().mini) { 26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delta += kMiniToNonMiniGap; 26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = model_index + 1; i < tab_count(); ++i) { 26085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect bounds = ideal_bounds(i); 26095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds.set_x(bounds.x() - delta); 26105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_ideal_bounds(i, bounds); 26115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) newtab_button_bounds_.set_x(newtab_button_bounds_.x() - delta); 26145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 26165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_closing->set_closing(true); 26185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We still need to paint the tab until we actually remove it. Put it in 26205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tabs_closing_map_ so we can find it. 26215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveTabFromViewModel(model_index); 26225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 26245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect tab_bounds = tab_closing->bounds(); 26265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_bounds.set_width(0); 26275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.AnimateViewTo(tab_closing, tab_bounds); 26285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Register delegate to do cleanup when done, BoundsAnimator takes 26305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ownership of RemoveTabDelegate. 26315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_animator_.SetAnimationDelegate( 26325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_closing, 26335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new RemoveTabDelegate(this, tab_closing), 26345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true); 26355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::IsPointInTab(Tab* tab, 26385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Point& point_in_tabstrip_coords) { 26395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Point point_in_tab_coords(point_in_tabstrip_coords); 26405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View::ConvertPointToTarget(this, tab, &point_in_tab_coords); 26415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab->HitTestPoint(point_in_tab_coords); 26425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStrip::GetStartXForNormalTabs() const { 26455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_tab_count = GetMiniTabCount(); 26465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mini_tab_count == 0) 26475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 26485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mini_tab_count * (Tab::GetMiniWidth() + tab_h_offset()) + 26495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMiniToNonMiniGap; 26505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab* TabStrip::FindTabForEvent(const gfx::Point& point) { 26532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (touch_layout_.get()) { 26542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int active_tab_index = touch_layout_->active_index(); 26552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (active_tab_index != -1) { 26562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Tab* tab = FindTabForEventFrom(point, active_tab_index, -1); 26572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!tab) 26582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tab = FindTabForEventFrom(point, active_tab_index + 1, 1); 26592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return tab; 26602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (tab_count()) { 26612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FindTabForEventFrom(point, 0, 1); 26622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 26632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 26642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 26652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsPointInTab(tab_at(i), point)) 26662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return tab_at(i); 26672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 26685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 26705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Tab* TabStrip::FindTabForEventFrom(const gfx::Point& point, 26735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start, 26745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta) { 26755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |start| equals tab_count() when there are only pinned tabs. 26765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start == tab_count()) 26775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start += delta; 26785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = start; i >= 0 && i < tab_count(); i += delta) { 26795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPointInTab(tab_at(i), point)) 26805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab_at(i); 26815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 26825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 26835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 26845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::View* TabStrip::FindTabHitByPoint(const gfx::Point& point) { 2686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The display order doesn't necessarily match the child list order, so we 2687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // walk the display list hit-testing Tabs. Since the active tab always 2688c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // renders on top of adjacent tabs, it needs to be hit-tested before any 2689c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // left-adjacent Tab, so we look ahead for it as we walk. 2690c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int i = 0; i < tab_count(); ++i) { 2691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Tab* next_tab = i < (tab_count() - 1) ? tab_at(i + 1) : NULL; 2692c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (next_tab && next_tab->IsActive() && IsPointInTab(next_tab, point)) 2693c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return next_tab; 2694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (IsPointInTab(tab_at(i), point)) 2695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return tab_at(i); 2696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 2699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 2700c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 27015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<int> TabStrip::GetTabXCoordinates() { 27025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<int> results; 27035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_count(); ++i) 27045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results.push_back(ideal_bounds(i).x()); 27055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return results; 27065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SwapLayoutIfNecessary() { 27095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool needs_touch = NeedsTouchLayout(); 27105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool using_touch = touch_layout_.get() != NULL; 27115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needs_touch == using_touch) 27125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 27135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needs_touch) { 27155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size tab_size(Tab::GetMinimumSelectedSize()); 27165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_size.set_width(Tab::GetTouchWidth()); 27172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) touch_layout_.reset(new StackedTabStripLayout( 27185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_size, 27195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_h_offset(), 27205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStackedPadding, 27215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxStackedCount, 27225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &tabs_)); 27235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetWidth(width() - new_tab_button_width()); 27245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This has to be after SetWidth() as SetWidth() is going to reset the 27252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // bounds of the mini-tabs (since StackedTabStripLayout doesn't yet know how 27265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // many mini-tabs there are). 27275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBoundsForMiniTabs(NULL); 27285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetXAndMiniCount(GetStartXForNormalTabs(), 27295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetMiniTabCount()); 27305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_->SetActiveIndex(controller_->GetActiveIndex()); 27315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 27325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) touch_layout_.reset(); 27335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 27345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrepareForAnimation(); 27355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GenerateIdealBounds(); 27365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AnimateToIdealBounds(); 27375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::NeedsTouchLayout() const { 27405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (layout_type_ == TAB_STRIP_LAYOUT_SHRINK) 27415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 27425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mini_tab_count = GetMiniTabCount(); 27445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int normal_count = tab_count() - mini_tab_count; 27455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (normal_count <= 1 || normal_count == mini_tab_count) 27465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 27475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = GetStartXForNormalTabs(); 27485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int available_width = width() - x - new_tab_button_width(); 27495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (Tab::GetTouchWidth() * normal_count + 27505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab_h_offset() * (normal_count - 1)) > available_width; 27515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStrip::SetResetToShrinkOnExit(bool value) { 27545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetAdjustLayout()) 27555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 27565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value && layout_type_ == TAB_STRIP_LAYOUT_SHRINK) 27585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value = false; // We're already at TAB_STRIP_LAYOUT_SHRINK. 27595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value == reset_to_shrink_on_exit_) 27615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 27625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reset_to_shrink_on_exit_ = value; 27645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add an observer so we know when the mouse moves out of the tabstrip. 27655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reset_to_shrink_on_exit_) 27665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddMessageLoopObserver(); 27675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 27685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveMessageLoopObserver(); 27695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 27705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStrip::GetAdjustLayout() const { 27725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!adjust_layout_) 27735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 27745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(USE_AURA) 2776f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return chrome::GetHostDesktopTypeForNativeView( 2777f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetWidget()->GetNativeView()) == chrome::HOST_DESKTOP_TYPE_ASH; 2778f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#else 27795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::GetDisplayLayout() != ui::LAYOUT_TOUCH) 27805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 27815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 27825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 27845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2785