summaryrefslogtreecommitdiffstats
path: root/sfx2/source/sidebar/TabBar.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sfx2/source/sidebar/TabBar.cxx417
1 files changed, 417 insertions, 0 deletions
diff --git a/sfx2/source/sidebar/TabBar.cxx b/sfx2/source/sidebar/TabBar.cxx
new file mode 100644
index 000000000..4f49bd461
--- /dev/null
+++ b/sfx2/source/sidebar/TabBar.cxx
@@ -0,0 +1,417 @@
+/* -*- 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 <sfx2/sidebar/TabBar.hxx>
+#include <sidebar/ControlFactory.hxx>
+#include <sidebar/DeckDescriptor.hxx>
+#include <sidebar/Paint.hxx>
+#include <sfx2/sidebar/Theme.hxx>
+#include <sidebar/Tools.hxx>
+#include <sfx2/sidebar/FocusManager.hxx>
+#include <sfx2/sidebar/SidebarController.hxx>
+#include <sfx2/strings.hrc>
+
+#include <sfx2/sfxresid.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/button.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/image.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/svborder.hxx>
+#include <svtools/acceleratorexecute.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+namespace sfx2::sidebar {
+
+TabBar::TabBar(vcl::Window* pParentWindow,
+ const Reference<frame::XFrame>& rxFrame,
+ const std::function<void (const OUString&)>& 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<DeckDescriptor> 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<DeckDescriptor> 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 ||
+ (rKeyCode.IsMod1() && rKeyCode.IsShift() && rKeyCode.GetCode() == KEY_F10))
+ 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<RadioButton> TabBar::CreateTabItem(const DeckDescriptor& rDeckDescriptor)
+{
+ VclPtr<RadioButton> 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 || o3tl::make_unsigned(nIndex)>=maItems.size())
+ throw RuntimeException();
+ return maItems[nIndex].msDeckId;
+}
+
+void TabBar::ToggleHideFlag (const sal_Int32 nIndex)
+{
+ if (nIndex<0 || o3tl::make_unsigned(nIndex) >= maItems.size())
+ throw RuntimeException();
+
+ maItems[nIndex].mbIsHidden = ! maItems[nIndex].mbIsHidden;
+
+ std::shared_ptr<DeckDescriptor> 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<DeckDescriptor> xDeckDescriptor = pParentSidebarController->GetResourceManager()->GetDeckDescriptor(item.msDeckId);
+ if (xDeckDescriptor)
+ xDeckDescriptor->mbIsEnabled = ! item.mbIsHidden;
+
+ }
+ }
+ if (bNeedsLayout)
+ Layout();
+}
+
+void TabBar::UpdateFocusManager(FocusManager& rFocusManager)
+{
+ std::vector<Button*> 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<DeckMenuData> aMenuData;
+
+ for (auto const& item : maItems)
+ {
+ std::shared_ptr<DeckDescriptor> 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);
+}
+
+void TabBar::EnableMenuButton(const bool bEnable)
+{
+ mpMenuButton->Enable(bEnable);
+}
+
+} // end of namespace sfx2::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */