// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "chrome/browser/simple_xp_frame.h" #include "chrome/app/theme/theme_resources.h" #include "base/string_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents.h" #include "chrome/browser/tab_contents_container_view.h" #include "chrome/browser/tabs/tab.h" #include "chrome/browser/views/location_bar_view.h" #include "chrome/browser/web_app.h" #include "chrome/browser/web_app_icon_manager.h" #include "chrome/browser/web_contents.h" #include "chrome/common/win_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/l10n_util.h" #include "chrome/views/focus_manager.h" #include "chrome/views/label.h" #include "chrome/views/text_field.h" #include "net/base/net_util.h" #include "SkBitmap.h" #include "generated_resources.h" // The title bar text color. static const SkColor kTitleBarTextColor = SkColorSetRGB(255, 255, 255); // How thick is the top resize bar. static const int kTopResizeBarHeight = 3; // Left margin on the left side of the favicon. static const int kFavIconMargin = 1; // Label offset. static const int kLabelVerticalOffset = -1; // Padding between the favicon and the text. static const int kFavIconPadding = 4; // Background color for the button hot state. static const SkColor kHotColor = SkColorSetRGB(49, 106, 197); // distance between contents and drop arrow. static const int kHorizMargin = 4; // Border all around the menu. static const int kHorizBorderSize = 2; static const int kVertBorderSize = 1; // How much wider or shorter the location bar is relative to the client area. static const int kLocationBarOffset = 2; // Spacing between the location bar and the content area. static const int kLocationBarSpacing = 1; //////////////////////////////////////////////////////////////////////////////// // // TitleBarMenuButton implementation. // //////////////////////////////////////////////////////////////////////////////// TitleBarMenuButton::TitleBarMenuButton(SimpleXPFrameTitleBar* title_bar) : ChromeViews::MenuButton(L"", title_bar, false), contents_(NULL), title_bar_(title_bar) { ResourceBundle &rb = ResourceBundle::GetSharedInstance(); drop_arrow_ = rb.GetBitmapNamed(IDR_APP_DROPARROW); } TitleBarMenuButton::~TitleBarMenuButton() { } void TitleBarMenuButton::SetContents(ChromeViews::View* contents) { contents_ = contents; } void TitleBarMenuButton::GetPreferredSize(CSize *out) { if (contents_) contents_->GetPreferredSize(out); else out->cx = out->cy = 0; out->cx += drop_arrow_->width() + kHorizMargin + (2 * kHorizBorderSize); out->cy = std::max(drop_arrow_->height(), static_cast(out->cy)); out->cy += (2 * kVertBorderSize); } void TitleBarMenuButton::Paint(ChromeCanvas* canvas) { if (GetState() == TextButton::BS_HOT || GetState() == TextButton::BS_PUSHED || menu_visible_) { canvas->FillRectInt(kHotColor, 0, 0, GetWidth(), GetHeight()); } if (contents_) { CSize s; contents_->GetPreferredSize(&s); // Note: we use a floating view in this case because we never want the // contents to process any event. PaintFloatingView(canvas, contents_, kVertBorderSize, (GetHeight() - s.cy) / 2, GetWidth() - kHorizMargin - drop_arrow_->width() - (2 * kHorizBorderSize), s.cy); } // We can not use the mirroring infrastructure in ChromeViews in order to // mirror the drop down arrow because is is drawn directly on the canvas // (instead of using a child View). Thus, we should mirror its position // manually. gfx::Rect arrow_bounds(GetWidth() - drop_arrow_->width() - kHorizBorderSize, (GetHeight() - drop_arrow_->height()) / 2, drop_arrow_->width(), drop_arrow_->height()); arrow_bounds.set_x(MirroredLeftPointForRect(arrow_bounds)); canvas->DrawBitmapInt(*drop_arrow_, arrow_bounds.x(), arrow_bounds.y()); } bool TitleBarMenuButton::OnMousePressed(const ChromeViews::MouseEvent& e) { if (e.GetFlags() & ChromeViews::MouseEvent::EF_IS_DOUBLE_CLICK) { if (!HitTest(WTL::CPoint(e.GetX(), e.GetY()))) return true; title_bar_->CloseWindow(); return true; } else { return MenuButton::OnMousePressed(e); } } //////////////////////////////////////////////////////////////////////////////// // // SimpleXPFrameTitleBar implementation. // //////////////////////////////////////////////////////////////////////////////// SimpleXPFrameTitleBar::SimpleXPFrameTitleBar(SimpleXPFrame* parent) : parent_(parent) { DCHECK(parent); tab_icon_.reset(new TabIconView(this)); tab_icon_->set_is_light(true); menu_button_ = new TitleBarMenuButton(this); menu_button_->SetContents(tab_icon_view()); AddChildView(menu_button_); tab_icon_->Update(); label_ = new ChromeViews::Label(); label_->SetColor(kTitleBarTextColor); label_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); AddChildView(label_); } SimpleXPFrameTitleBar::~SimpleXPFrameTitleBar() { } TabContents* SimpleXPFrameTitleBar::GetCurrentTabContents() { return parent_->GetCurrentContents(); } SkBitmap SimpleXPFrameTitleBar::GetFavIcon() { // Only use the favicon if we're a web application. TabContents* contents = GetCurrentTabContents(); if (parent_->IsApplication()) { TabContents* contents = GetCurrentTabContents(); WebContents* web_contents = contents->AsWebContents(); if (web_contents) { // If it's a web contents, pull the favicon from the WebApp, and fallback // to the icon. WebApp* web_app = web_contents->web_app(); if (web_app && !web_app->GetFavIcon().isNull()) return web_app->GetFavIcon(); } if (contents) { SkBitmap favicon = contents->GetFavIcon(); if (!favicon.isNull()) return favicon; } } // Otherwise, use the default icon. return SkBitmap(); } void SimpleXPFrameTitleBar::RunMenu(ChromeViews::View* source, const CPoint& pt, HWND hwnd) { // Make sure we calculate the menu position based on the display bounds of // the menu button. The display bounds are different than the actual bounds // when the UI layout is RTL and hence we use the mirroring transformation // flag. We also adjust the menu position because RTL menus use a different // anchor point. CPoint p(menu_button_->GetX(APPLY_MIRRORING_TRANSFORMATION), menu_button_->GetY() + menu_button_->GetHeight()); if (UILayoutIsRightToLeft()) p.x += menu_button_->GetWidth(); View::ConvertPointToScreen(this, &p); parent_->RunMenu(p, hwnd); } void SimpleXPFrameTitleBar::Layout() { CSize s; menu_button_->GetPreferredSize(&s); menu_button_->SetBounds(kFavIconMargin, (GetHeight() - s.cy) / 2, s.cx, s.cy); menu_button_->Layout(); label_->SetBounds(menu_button_->GetX() + menu_button_->GetWidth() + kFavIconPadding, kLabelVerticalOffset, GetWidth() - (menu_button_->GetX() + menu_button_->GetWidth() + kFavIconPadding), GetHeight()); } bool SimpleXPFrameTitleBar::WillHandleMouseEvent(int x, int y) { // If the locale is RTL, we must query for the bounds of the menu button in // a way that returns the mirrored position and not the position set using // SetX()/SetBounds(). CPoint p(x - menu_button_->GetX(APPLY_MIRRORING_TRANSFORMATION), y - menu_button_->GetY()); return menu_button_->HitTest(p); } void SimpleXPFrameTitleBar::SetWindowTitle(std::wstring s) { if (parent_->IsApplication()) { std::wstring t(s); Browser::FormatTitleForDisplay(&t); label_->SetText(t); } else { label_->SetText(Browser::ComputePopupTitle( GetCurrentTabContents()->GetURL(), s)); } } void SimpleXPFrameTitleBar::ValidateThrobber() { tab_icon_->Update(); menu_button_->SchedulePaint(); } void SimpleXPFrameTitleBar::CloseWindow() { parent_->Close(); } void SimpleXPFrameTitleBar::Update() { tab_icon_->Update(); } //////////////////////////////////////////////////////////////////////////////// // // SimpleXPFrame implementation. // //////////////////////////////////////////////////////////////////////////////// // static SimpleXPFrame* SimpleXPFrame::CreateFrame(const gfx::Rect& bounds, Browser* browser) { SimpleXPFrame* instance = new SimpleXPFrame(browser); instance->Create(NULL, bounds.ToRECT(), l10n_util::GetString(IDS_PRODUCT_NAME).c_str()); instance->InitAfterHWNDCreated(); instance->SetIsOffTheRecord(browser->profile()->IsOffTheRecord()); ChromeViews::FocusManager::CreateFocusManager(instance->m_hWnd, instance->GetRootView()); return instance; } SimpleXPFrame::SimpleXPFrame(Browser* browser) : XPFrame(browser), title_bar_(NULL), location_bar_(NULL) { } void SimpleXPFrame::InitAfterHWNDCreated() { icon_manager_.reset(new WebAppIconManager(*this)); XPFrame::InitAfterHWNDCreated(); } SimpleXPFrame::~SimpleXPFrame() { } void SimpleXPFrame::Init() { XPFrame::Init(); if (IsTitleBarVisible()) { title_bar_ = new SimpleXPFrameTitleBar(this); GetFrameView()->AddChildView(title_bar_); } location_bar_ = new LocationBarView(browser_->profile(), browser_->controller(), browser_->toolbar_model(), this, true); GetFrameView()->AddChildView(location_bar_); location_bar_->Init(); // Constrained popups that were unconstrained will need to set up a // throbber. UpdateTitleBar(); } TabContents* SimpleXPFrame::GetCurrentContents() { if (browser_) return browser_->GetSelectedTabContents(); else return NULL; } void SimpleXPFrame::Layout() { XPFrame::Layout(); if (IsTitleBarVisible()) { TabContentsContainerView* tccv = GetTabContentsContainer(); DCHECK(tccv); title_bar_->SetBounds(tccv->GetX(), 0, GetButtonXOrigin() - tccv->GetX(), GetContentsYOrigin()); title_bar_->Layout(); } if (browser_->ShouldDisplayURLField()) { TabContentsContainerView* container = GetTabContentsContainer(); CSize s; location_bar_->GetPreferredSize(&s); location_bar_->SetBounds(container->GetX() - kLocationBarOffset, container->GetY(), container->GetWidth() + kLocationBarOffset * 2, s.cy); container->SetBounds(container->GetX(), location_bar_->GetY() + location_bar_->GetHeight() + kLocationBarSpacing, container->GetWidth(), container->GetHeight() - location_bar_->GetHeight() - 1); location_bar_->SetVisible(true); location_bar_->Layout(); } else { location_bar_->SetVisible(false); } } LRESULT SimpleXPFrame::OnNCHitTest(const CPoint& pt) { if (IsTitleBarVisible()) { CPoint p(pt); ChromeViews::View::ConvertPointToView(NULL, title_bar_, &p); if (!title_bar_->WillHandleMouseEvent(p.x, p.y) && p.x >= 0 && p.y >= kTopResizeBarHeight && p.x < title_bar_->GetWidth() && p.y < title_bar_->GetHeight()) { return HTCAPTION; } } return XPFrame::OnNCHitTest(pt); } void SimpleXPFrame::SetWindowTitle(const std::wstring& title) { if (IsTitleBarVisible()) title_bar_->SetWindowTitle(title); XPFrame::SetWindowTitle(title); } void SimpleXPFrame::UpdateTitleBar() { if (IsTitleBarVisible()) { title_bar_->Update(); title_bar_->SchedulePaint(); } UpdateLocationBar(); } void SimpleXPFrame::ValidateThrobber() { if (IsTitleBarVisible()) title_bar_->ValidateThrobber(); } void SimpleXPFrame::RunMenu(const CPoint& pt, HWND hwnd) { browser_->RunSimpleFrameMenu(pt, hwnd); } void SimpleXPFrame::ShowTabContents(TabContents* selected_contents) { XPFrame::ShowTabContents(selected_contents); icon_manager_->SetContents(selected_contents); UpdateLocationBar(); } bool SimpleXPFrame::IsApplication() const { return browser_->IsApplication(); } void SimpleXPFrame::UpdateLocationBar() { if (location_bar_ && location_bar_->IsVisible()) location_bar_->Update(NULL); } TabContents* SimpleXPFrame::GetTabContents() { return GetCurrentContents(); } void SimpleXPFrame::OnInputInProgress(bool in_progress) { }