/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace css; using namespace css::uno; namespace sfx2 { namespace sidebar { TabBar::TabBar(vcl::Window* pParentWindow, const Reference& rxFrame, const std::function& rDeckActivationFunctor, const PopupMenuProvider& rPopupMenuProvider, SidebarController* rParentSidebarController ) : Window(pParentWindow, WB_DIALOGCONTROL), mxFrame(rxFrame), mpMenuButton(ControlFactory::CreateMenuButton(this)), maItems(), maDeckActivationFunctor(rDeckActivationFunctor), maPopupMenuProvider(rPopupMenuProvider), pParentSidebarController(rParentSidebarController) { SetBackground(Theme::GetPaint(Theme::Paint_TabBarBackground).GetWallpaper()); mpMenuButton->SetModeImage(Theme::GetImage(Theme::Image_TabBarMenu)); mpMenuButton->SetClickHdl(LINK(this, TabBar, OnToolboxClicked)); mpMenuButton->SetQuickHelpText(SfxResId(SFX_STR_SIDEBAR_SETTINGS)); Layout(); #ifdef DEBUG SetText(OUString("TabBar")); #endif } TabBar::~TabBar() { disposeOnce(); } void TabBar::dispose() { for (auto & item : maItems) item.mpButton.disposeAndClear(); maItems.clear(); mpMenuButton.disposeAndClear(); vcl::Window::dispose(); } void TabBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rUpdateArea) { Window::Paint(rRenderContext, rUpdateArea); const sal_Int32 nHorizontalPadding(Theme::GetInteger(Theme::Int_TabMenuSeparatorPadding)); rRenderContext.SetLineColor(Theme::GetColor(Theme::Color_TabMenuSeparator)); rRenderContext.DrawLine(Point(nHorizontalPadding, mnMenuSeparatorY), Point(GetSizePixel().Width() - nHorizontalPadding, mnMenuSeparatorY)); } sal_Int32 TabBar::GetDefaultWidth() { return Theme::GetInteger(Theme::Int_TabItemWidth) + Theme::GetInteger(Theme::Int_TabBarLeftPadding) + Theme::GetInteger(Theme::Int_TabBarRightPadding); } void TabBar::SetDecks(const ResourceManager::DeckContextDescriptorContainer& rDecks) { // Remove the current buttons. { for (auto & item : maItems) { item.mpButton.disposeAndClear(); } maItems.clear(); } maItems.resize(rDecks.size()); sal_Int32 nIndex (0); for (auto const& deck : rDecks) { std::shared_ptr xDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(deck.msId); if (xDescriptor == nullptr) { OSL_ASSERT(xDescriptor!=nullptr); continue; } Item& rItem (maItems[nIndex++]); rItem.msDeckId = xDescriptor->msId; rItem.mpButton.disposeAndClear(); rItem.mpButton = CreateTabItem(*xDescriptor); rItem.mpButton->SetClickHdl(LINK(&rItem, TabBar::Item, HandleClick)); rItem.maDeckActivationFunctor = maDeckActivationFunctor; rItem.mbIsHidden = ! xDescriptor->mbIsEnabled; rItem.mbIsHiddenByDefault = rItem.mbIsHidden; // the default is the state while creating rItem.mpButton->Enable(deck.mbIsEnabled); } UpdateButtonIcons(); Layout(); } void TabBar::UpdateButtonIcons() { Image aImage = Theme::GetImage(Theme::Image_TabBarMenu); mpMenuButton->SetModeImage(aImage); for (auto const& item : maItems) { std::shared_ptr xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item.msDeckId); if (xDeckDescriptor) { aImage = GetItemImage(*xDeckDescriptor); item.mpButton->SetModeImage(aImage); } } Invalidate(); } void TabBar::Layout() { const SvBorder aPadding ( Theme::GetInteger(Theme::Int_TabBarLeftPadding), Theme::GetInteger(Theme::Int_TabBarTopPadding), Theme::GetInteger(Theme::Int_TabBarRightPadding), Theme::GetInteger(Theme::Int_TabBarBottomPadding)); sal_Int32 nX (aPadding.Top()); sal_Int32 nY (aPadding.Left()); const Size aTabItemSize ( Theme::GetInteger(Theme::Int_TabItemWidth) * GetDPIScaleFactor(), Theme::GetInteger(Theme::Int_TabItemHeight) * GetDPIScaleFactor()); // Place the menu button and the separator. if (mpMenuButton != nullptr) { mpMenuButton->SetPosSizePixel( Point(nX,nY), aTabItemSize); mpMenuButton->Show(); nY += mpMenuButton->GetSizePixel().Height() + 1 + Theme::GetInteger(Theme::Int_TabMenuPadding); mnMenuSeparatorY = nY - Theme::GetInteger(Theme::Int_TabMenuPadding)/2 - 1; } // Place the deck selection buttons. for (auto const& item : maItems) { Button& rButton (*item.mpButton); rButton.Show( ! item.mbIsHidden); if (item.mbIsHidden) continue; // Place and size the icon. rButton.SetPosSizePixel( Point(nX,nY), aTabItemSize); rButton.Show(); nY += rButton.GetSizePixel().Height() + 1 + aPadding.Bottom(); } Invalidate(); } void TabBar::HighlightDeck (const OUString& rsDeckId) { for (auto const& item : maItems) { if (item.msDeckId == rsDeckId) item.mpButton->Check(); else item.mpButton->Check(false); } } void TabBar::RemoveDeckHighlight () { for (auto const& item : maItems) { item.mpButton->Check(false); } } void TabBar::DataChanged (const DataChangedEvent& rDataChangedEvent) { SetBackground(Theme::GetPaint(Theme::Paint_TabBarBackground).GetWallpaper()); UpdateButtonIcons(); Window::DataChanged(rDataChangedEvent); } bool TabBar::EventNotify(NotifyEvent& rEvent) { MouseNotifyEvent nType = rEvent.GetType(); if(MouseNotifyEvent::KEYINPUT == nType) { const vcl::KeyCode& rKeyCode = rEvent.GetKeyEvent()->GetKeyCode(); if (!mpAccel) { mpAccel = svt::AcceleratorExecute::createAcceleratorHelper(); mpAccel->init(comphelper::getProcessComponentContext(), mxFrame); } const OUString aCommand(mpAccel->findCommand(svt::AcceleratorExecute::st_VCLKey2AWTKey(rKeyCode))); if (".uno:Sidebar" == aCommand) return vcl::Window::EventNotify(rEvent); return true; } else if(MouseNotifyEvent::COMMAND == nType) { const CommandEvent& rCommandEvent = *rEvent.GetCommandEvent(); if(rCommandEvent.GetCommand() == CommandEventId::Wheel) { const CommandWheelData* pData = rCommandEvent.GetWheelData(); if(!pData->GetModifier() && (pData->GetMode() == CommandWheelMode::SCROLL)) { auto pItem = std::find_if(maItems.begin(), maItems.end(), [] (Item const& rItem) { return rItem.mpButton->IsChecked(); }); if(pItem == maItems.end()) return true; if(pData->GetNotchDelta()<0) { if(pItem+1 == maItems.end()) return true; ++pItem; } else { if(pItem == maItems.begin()) return true; --pItem; } try { pItem->maDeckActivationFunctor(pItem->msDeckId); } catch(const css::uno::Exception&) {}; return true; } } } return false; } VclPtr TabBar::CreateTabItem(const DeckDescriptor& rDeckDescriptor) { VclPtr pItem = ControlFactory::CreateTabItem(this); pItem->SetAccessibleName(rDeckDescriptor.msTitle); pItem->SetAccessibleDescription(rDeckDescriptor.msHelpText); pItem->SetHelpText(rDeckDescriptor.msHelpText); pItem->SetQuickHelpText(rDeckDescriptor.msHelpText); return pItem; } Image TabBar::GetItemImage(const DeckDescriptor& rDeckDescriptor) const { return Tools::GetImage( rDeckDescriptor.msIconURL, rDeckDescriptor.msHighContrastIconURL, mxFrame); } IMPL_LINK_NOARG(TabBar::Item, HandleClick, Button*, void) { vcl::Window* pFocusWin = Application::GetFocusWindow(); pFocusWin->GrabFocusToDocument(); try { maDeckActivationFunctor(msDeckId); } catch(const css::uno::Exception&) {} // workaround for #i123198# } OUString const & TabBar::GetDeckIdForIndex (const sal_Int32 nIndex) const { if (nIndex<0 || static_cast(nIndex)>=maItems.size()) throw RuntimeException(); return maItems[nIndex].msDeckId; } void TabBar::ToggleHideFlag (const sal_Int32 nIndex) { if (nIndex<0 || static_cast(nIndex) >= maItems.size()) throw RuntimeException(); maItems[nIndex].mbIsHidden = ! maItems[nIndex].mbIsHidden; std::shared_ptr xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(maItems[nIndex].msDeckId); if (xDeckDescriptor) { xDeckDescriptor->mbIsEnabled = ! maItems[nIndex].mbIsHidden; Context aContext; aContext.msApplication = pParentSidebarController->GetCurrentContext().msApplication; // leave aContext.msContext on default 'any' ... this func is used only for decks // and we don't have context-sensitive decks anyway xDeckDescriptor->maContextList.ToggleVisibilityForContext( aContext, xDeckDescriptor->mbIsEnabled ); } Layout(); } void TabBar::RestoreHideFlags() { bool bNeedsLayout(false); for (auto & item : maItems) { if (item.mbIsHidden != item.mbIsHiddenByDefault) { item.mbIsHidden = item.mbIsHiddenByDefault; bNeedsLayout = true; std::shared_ptr xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item.msDeckId); if (xDeckDescriptor) xDeckDescriptor->mbIsEnabled = ! item.mbIsHidden; } } if (bNeedsLayout) Layout(); } void TabBar::UpdateFocusManager(FocusManager& rFocusManager) { std::vector aButtons; aButtons.reserve(maItems.size()+1); aButtons.push_back(mpMenuButton.get()); for (auto const& item : maItems) { aButtons.push_back(item.mpButton.get()); } rFocusManager.SetButtons(aButtons); } IMPL_LINK_NOARG(TabBar, OnToolboxClicked, Button*, void) { if (!mpMenuButton) return; std::vector aMenuData; for (auto const& item : maItems) { std::shared_ptr xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item.msDeckId); if (xDeckDescriptor) { DeckMenuData aData; aData.msDisplayName = xDeckDescriptor->msTitle; aData.mbIsCurrentDeck = item.mpButton->IsChecked(); aData.mbIsActive = !item.mbIsHidden; aData.mbIsEnabled = item.mpButton->IsEnabled(); aMenuData.push_back(aData); } } maPopupMenuProvider( tools::Rectangle( mpMenuButton->GetPosPixel(), mpMenuButton->GetSizePixel()), aMenuData); mpMenuButton->Check(false); } } } // end of namespace sfx2::sidebar /* vim:set shiftwidth=4 softtabstop=4 expandtab: */