diff options
Diffstat (limited to 'chrome/browser/views/tabs/tab.cc')
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc new file mode 100644 index 0000000..bf5dc89 --- /dev/null +++ b/chrome/browser/views/tabs/tab.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/tabs/tab.h" + +#include "base/gfx/size.h" +#include "chrome/views/view_container.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/path.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/views/chrome_menu.h" +#include "chrome/views/tooltip_manager.h" +#include "generated_resources.h" + +const std::string Tab::kTabClassName = "browser/tabs/Tab"; + +static const SkScalar kTabCapWidth = 15; +static const SkScalar kTabTopCurveWidth = 4; +static const SkScalar kTabBottomCurveWidth = 3; + +class TabContextMenuController : public ChromeViews::MenuDelegate { + public: + explicit TabContextMenuController(Tab* tab) + : tab_(tab), + last_command_(TabStripModel::CommandFirst) { + menu_.reset(new ChromeViews::MenuItemView(this)); + menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab, + l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB)); + menu_->AppendSeparator(); + menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload, + l10n_util::GetString(IDS_TAB_CXMENU_RELOAD)); + menu_->AppendMenuItemWithLabel( + TabStripModel::CommandDuplicate, + l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE)); + menu_->AppendSeparator(); + menu_->AppendMenuItemWithLabel( + TabStripModel::CommandCloseTab, + l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB)); + menu_->AppendMenuItemWithLabel( + TabStripModel::CommandCloseOtherTabs, + l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS)); + menu_->AppendMenuItemWithLabel( + TabStripModel::CommandCloseTabsToRight, + l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT)); + menu_->AppendMenuItemWithLabel( + TabStripModel::CommandCloseTabsOpenedBy, + l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY)); + } + virtual ~TabContextMenuController() { + tab_->delegate()->StopAllHighlighting(); + } + + void RunMenuAt(int x, int y) { + menu_->RunMenuAt(tab_->GetViewContainer()->GetHWND(), + gfx::Rect(x, y, 0, 0), ChromeViews::MenuItemView::TOPLEFT, + false); + } + + private: + // ChromeViews::MenuDelegate implementation: + virtual bool IsCommandEnabled(int id) const { + // The MenuItemView used to contain the contents of the Context Menu itself + // has a command id of 0, and it will check to see if it's enabled for + // some reason during its construction. The TabStripModel can't handle + // command indices it doesn't know about, so we need to filter this out + // here. + if (id == 0) + return false; + return tab_->delegate()->IsCommandEnabledForTab( + static_cast<TabStripModel::ContextMenuCommand>(id), + tab_); + } + + virtual void ExecuteCommand(int id) { + tab_->delegate()->ExecuteCommandForTab( + static_cast<TabStripModel::ContextMenuCommand>(id), + tab_); + } + + virtual void SelectionChanged(ChromeViews::MenuItemView* menu) { + TabStripModel::ContextMenuCommand command = + static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand()); + tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_); + last_command_ = command; + tab_->delegate()->StartHighlightTabsForCommand(command, tab_); + } + + private: + // The context menu. + scoped_ptr<ChromeViews::MenuItemView> menu_; + + // The Tab the context menu was brought up for. + Tab* tab_; + + // The last command that was selected, so that we can start/stop highlighting + // appropriately as the user moves through the menu. + TabStripModel::ContextMenuCommand last_command_; + + DISALLOW_EVIL_CONSTRUCTORS(TabContextMenuController); +}; + +/////////////////////////////////////////////////////////////////////////////// +// Tab, public: + +Tab::Tab(TabDelegate* delegate) + : TabRenderer(), + delegate_(delegate), + closing_(false) { + close_button()->SetListener(this, 0); + close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); + close_button()->SetAnimationDuration(0); + SetContextMenuController(this); +} + +Tab::~Tab() { +} + +/////////////////////////////////////////////////////////////////////////////// +// Tab, TabRenderer overrides: + +bool Tab::IsSelected() const { + return delegate_->IsTabSelected(this); +} + +/////////////////////////////////////////////////////////////////////////////// +// Tab, ChromeViews::View overrides: + +bool Tab::HitTest(const CPoint &l) const { + gfx::Path path; + MakePathForTab(&path); + ScopedHRGN rgn(path.CreateHRGN()); + return !!PtInRegion(rgn, l.x, l.y); +} + +bool Tab::OnMousePressed(const ChromeViews::MouseEvent& event) { + if (event.IsOnlyLeftMouseButton()) { + // Store whether or not we were selected just now... we only want to be + // able to drag foreground tabs, so we don't start dragging the tab if + // it was in the background. + bool just_selected = !IsSelected(); + if (just_selected) + delegate_->SelectTab(this); + delegate_->MaybeStartDrag(this, event); + } + return true; +} + +bool Tab::OnMouseDragged(const ChromeViews::MouseEvent& event) { + delegate_->ContinueDrag(event); + return true; +} + +void Tab::OnMouseReleased(const ChromeViews::MouseEvent& event, + bool canceled) { + // Notify the drag helper that we're done with any potential drag operations. + // Clean up the drag helper, which is re-created on the next mouse press. + delegate_->EndDrag(canceled); + if (event.IsMiddleMouseButton()) + delegate_->CloseTab(this); +} + +bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) { + std::wstring title = GetTitle(); + if (!title.empty()) { + // Only show the tooltip if the title is truncated. + ChromeFont font; + if (font.GetStringWidth(title) > title_bounds().width()) { + *tooltip = title; + return true; + } + } + return false; +} + +bool Tab::GetTooltipTextOrigin(int x, int y, CPoint* origin) { + ChromeFont font; + origin->x = title_bounds().x() + 10; + origin->y = -ChromeViews::TooltipManager::GetTooltipHeight() - 4; + return true; +} + +bool Tab::GetAccessibleRole(VARIANT* role) { + DCHECK(role); + + role->vt = VT_I4; + role->lVal = ROLE_SYSTEM_PAGETAB; + return true; +} + +bool Tab::GetAccessibleName(std::wstring* name) { + *name = GetTitle(); + return !name->empty(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Tab, ChromeViews::ContextMenuController implementation: + +void Tab::ShowContextMenu(ChromeViews::View* source, int x, int y, + bool is_mouse_gesture) { + TabContextMenuController controller(this); + controller.RunMenuAt(x, y); +} + + +/////////////////////////////////////////////////////////////////////////////// +// ChromeViews::BaseButton::ButtonListener implementation: + +void Tab::ButtonPressed(ChromeViews::BaseButton* sender) { + if (sender == close_button()) + delegate_->CloseTab(this); +} + +/////////////////////////////////////////////////////////////////////////////// +// Tab, private: + +void Tab::MakePathForTab(gfx::Path* path) const { + DCHECK(path); + + SkScalar h = SkIntToScalar(GetHeight()); + SkScalar w = SkIntToScalar(GetWidth()); + + path->moveTo(0, h); + + // Left end cap. + path->lineTo(kTabBottomCurveWidth, h - kTabBottomCurveWidth); + path->lineTo(kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth); + path->lineTo(kTabCapWidth, 0); + + // Connect to the right cap. + path->lineTo(w - kTabCapWidth, 0); + + // Right end cap. + path->lineTo(w - kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth); + path->lineTo(w - kTabBottomCurveWidth, h - kTabBottomCurveWidth); + path->lineTo(w, h); + + // Close out the path. + path->lineTo(0, h); + path->close(); +} |