1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <boost/property_tree/ptree.hpp>
26 #include <vcl/svapp.hxx>
27 #include <vcl/idle.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/toolbox.hxx>
30 #include <vcl/mnemonic.hxx>
31 #include <vcl/menu.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/IconThemeInfo.hxx>
34 #include <vcl/commandinfoprovider.hxx>
40 #include <unotools/confignode.hxx>
44 #define TB_SEP_SIZE 8 // Separator size
47 ImplToolBoxPrivateData::ImplToolBoxPrivateData()
49 meButtonSize
= ToolBoxButtonSize::DontCare
;
50 mpMenu
= VclPtr
<PopupMenu
>::Create();
52 maMenuType
= ToolBoxMenuType::NONE
;
53 maMenubuttonItem
.maItemSize
= Size( TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
, TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
);
54 maMenubuttonItem
.meState
= TRISTATE_FALSE
;
55 mnMenuButtonWidth
= TB_MENUBUTTON_SIZE
;
58 mbNativeButtons
= false;
59 mbIsPaintLocked
= false;
60 mbAssumeDocked
= false;
61 mbAssumePopupMode
= false;
62 mbAssumeFloating
= false;
63 mbKeyInputDisabled
= false;
64 mbMenubuttonSelected
= false;
65 mbMenubuttonWasLastSelected
= false;
66 mbWillUsePopupMode
= false;
67 mbDropDownByKeyboard
= false;
70 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
72 m_pLayoutData
.reset();
73 mpMenu
.disposeAndClear();
76 void ImplToolItem::init(sal_uInt16 nItemId
, ToolBoxItemBits nItemBits
,
82 meType
= ToolBoxItemType::BUTTON
;
84 meState
= TRISTATE_FALSE
;
87 mbEmptyBtn
= bEmptyBtn
;
90 mnSepSize
= TB_SEP_SIZE
;
91 mnDropDownArrowWidth
= TB_DROPDOWNARROWWIDTH
;
94 mbVisibleText
= false;
98 ImplToolItem::ImplToolItem()
100 init(0, ToolBoxItemBits::NONE
, true);
103 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
104 ToolBoxItemBits nItemBits
) :
107 init(nItemId
, nItemBits
, false);
110 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const OUString
& rText
,
111 ToolBoxItemBits nItemBits
) :
114 init(nItemId
, nItemBits
, false);
117 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
118 const OUString
& rText
, ToolBoxItemBits nItemBits
) :
122 init(nItemId
, nItemBits
, false);
125 Size
ImplToolItem::GetSize( bool bHorz
, bool bCheckMaxWidth
, long maxWidth
, const Size
& rDefaultSize
)
127 Size
aSize( rDefaultSize
); // the size of 'standard' toolbox items
128 // non-standard items are eg windows or buttons with text
130 if ( (meType
== ToolBoxItemType::BUTTON
) || (meType
== ToolBoxItemType::SPACE
) )
134 if ( mpWindow
&& bHorz
)
136 // get size of item window and check if it fits
137 // no windows in vertical toolbars (the default is mbShowWindow=false)
138 Size aWinSize
= mpWindow
->GetSizePixel();
140 if (mpWindow
->GetStyle() & WB_NOLABEL
)
141 // Window wants no label? Then don't check width, it'll be just
143 bCheckMaxWidth
= false;
145 if ( !bCheckMaxWidth
|| (aWinSize
.Width() <= maxWidth
) )
147 aSize
.setWidth( aWinSize
.Width() );
148 aSize
.setHeight( aWinSize
.Height() );
156 aSize
.setHeight( 0 );
161 else if ( meType
== ToolBoxItemType::SEPARATOR
)
165 aSize
.setWidth( mnSepSize
);
166 aSize
.setHeight( rDefaultSize
.Height() );
170 aSize
.setWidth( rDefaultSize
.Width() );
171 aSize
.setHeight( mnSepSize
);
174 else if ( meType
== ToolBoxItemType::BREAK
)
177 aSize
.setHeight( 0 );
183 void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType
, bool& rbImage
, bool& rbText
) const
185 if ( meType
!= ToolBoxItemType::BUTTON
)
187 // no button -> draw nothing
188 rbImage
= rbText
= false;
195 // check for image and/or text
196 bHasImage
= !!maImage
;
197 bHasText
= !maText
.isEmpty();
199 // prefer images if symbolonly buttons are drawn
200 // prefer texts if textonly buttons are drawn
202 if ( eButtonType
== ButtonType::SYMBOLONLY
) // drawing icons only
204 if( bHasImage
|| !bHasText
)
215 else if ( eButtonType
== ButtonType::TEXT
) // drawing text only
217 if( bHasText
|| !bHasImage
)
228 else // drawing icons and text both
235 tools::Rectangle
ImplToolItem::GetDropDownRect( bool bHorz
) const
237 tools::Rectangle aRect
;
238 if( (mnBits
& ToolBoxItemBits::DROPDOWN
) && !maRect
.IsEmpty() )
241 if( mbVisibleText
&& !bHorz
)
242 // item will be rotated -> place dropdown to the bottom
243 aRect
.SetTop( aRect
.Bottom() - mnDropDownArrowWidth
);
245 // place dropdown to the right
246 aRect
.SetLeft( aRect
.Right() - mnDropDownArrowWidth
);
251 bool ImplToolItem::IsClipped() const
253 return ( meType
== ToolBoxItemType::BUTTON
&& mbVisible
&& maRect
.IsEmpty() );
256 bool ImplToolItem::IsItemHidden() const
258 return ( meType
== ToolBoxItemType::BUTTON
&& !mbVisible
);
261 void ToolBox::ImplInvalidate( bool bNewCalc
, bool bFullPaint
)
263 ImplUpdateInputEnable();
272 // do we need to redraw?
273 if ( IsReallyVisible() && IsUpdateMode() )
275 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
,
276 mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
286 // do we need to redraw?
287 if ( IsReallyVisible() && IsUpdateMode() )
292 // request new layout by layoutmanager
293 CallEventListeners( VclEventId::ToolboxFormatChanged
);
296 void ToolBox::ImplUpdateItem( ImplToolItems::size_type nIndex
)
298 // do we need to redraw?
299 if ( IsReallyVisible() && IsUpdateMode() )
301 if ( nIndex
== ITEM_NOTFOUND
)
303 // #i52217# no immediate draw as this might lead to paint problems
304 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
310 // #i52217# no immediate draw as this might lead to paint problems
311 Invalidate( mpData
->m_aItems
[nIndex
].maRect
);
314 maPaintRect
.Union( mpData
->m_aItems
[nIndex
].maRect
);
319 void ToolBox::Click()
321 CallEventListeners( VclEventId::ToolboxClick
);
322 maClickHdl
.Call( this );
325 void ToolBox::DoubleClick()
327 CallEventListeners( VclEventId::ToolboxDoubleClick
);
328 maDoubleClickHdl
.Call( this );
331 void ToolBox::Activate()
334 CallEventListeners( VclEventId::ToolboxActivate
);
335 maActivateHdl
.Call( this );
338 void ToolBox::Deactivate()
341 CallEventListeners( VclEventId::ToolboxDeactivate
);
342 maDeactivateHdl
.Call( this );
345 void ToolBox::Highlight()
347 CallEventListeners( VclEventId::ToolboxHighlight
);
350 void ToolBox::Select()
352 VclPtr
<vcl::Window
> xWindow
= this;
354 CallEventListeners( VclEventId::ToolboxSelect
);
355 maSelectHdl
.Call( this );
357 if ( xWindow
->IsDisposed() )
360 // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
361 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
362 if( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() )
363 pWrapper
->GetFloatingWindow()->EndPopupMode();
366 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
368 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
369 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
370 "ToolBox::InsertItem(): ItemId already exists" );
372 // create item and add to list
373 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
374 ImplToolItem( nItemId
, rImage
, nBits
) );
375 mpData
->ImplClearLayoutData();
377 ImplInvalidate( true );
380 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
381 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >(nNewPos
) );
384 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, const OUString
& rText
, ToolBoxItemBits nBits
,
385 ImplToolItems::size_type nPos
)
387 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
388 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
389 "ToolBox::InsertItem(): ItemId already exists" );
391 // create item and add to list
392 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
393 ImplToolItem( nItemId
, rImage
, MnemonicGenerator::EraseAllMnemonicChars(rText
), nBits
) );
394 mpData
->ImplClearLayoutData();
396 ImplInvalidate( true );
399 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
400 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
403 void ToolBox::InsertItem( sal_uInt16 nItemId
, const OUString
& rText
, ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
405 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
406 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
407 "ToolBox::InsertItem(): ItemId already exists" );
409 // create item and add to list
410 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
411 ImplToolItem( nItemId
, MnemonicGenerator::EraseAllMnemonicChars(rText
), nBits
) );
412 mpData
->ImplClearLayoutData();
414 ImplInvalidate( true );
417 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
418 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
421 void ToolBox::InsertItem(const OUString
& rCommand
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
, ToolBoxItemBits nBits
,
422 const Size
& rRequestedSize
, ImplToolItems::size_type nPos
)
424 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
425 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(rCommand
, aModuleName
);
426 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
427 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(rCommand
, aProperties
, rFrame
));
428 Image
aImage(CommandInfoProvider::GetImageForCommand(rCommand
, rFrame
, GetImageSize()));
430 sal_uInt16 nItemId
= GetItemCount() + 1;
431 //TODO: ImplToolItems::size_type -> sal_uInt16!
432 InsertItem(nItemId
, aImage
, aLabel
, nBits
, nPos
);
433 SetItemCommand(nItemId
, rCommand
);
434 SetQuickHelpText(nItemId
, aTooltip
);
436 // set the minimal size
437 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
439 pItem
->maMinimalItemSize
= rRequestedSize
;
442 void ToolBox::InsertWindow( sal_uInt16 nItemId
, vcl::Window
* pWindow
,
443 ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
445 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertWindow(): ItemId == 0" );
446 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
447 "ToolBox::InsertWindow(): ItemId already exists" );
449 // create item and add to list
451 aItem
.mnId
= nItemId
;
452 aItem
.meType
= ToolBoxItemType::BUTTON
;
453 aItem
.mnBits
= nBits
;
454 aItem
.mpWindow
= pWindow
;
455 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
456 mpData
->ImplClearLayoutData();
461 ImplInvalidate( true );
464 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
465 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
468 void ToolBox::InsertSpace()
470 // create item and add to list
472 aItem
.meType
= ToolBoxItemType::SPACE
;
473 aItem
.mbEnabled
= false;
474 mpData
->m_aItems
.push_back( aItem
);
475 mpData
->ImplClearLayoutData();
480 ImplToolItems::size_type nNewPos
= mpData
->m_aItems
.size() - 1;
481 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
484 void ToolBox::InsertSeparator( ImplToolItems::size_type nPos
, sal_uInt16 nPixSize
)
486 // create item and add to list
488 aItem
.meType
= ToolBoxItemType::SEPARATOR
;
489 aItem
.mbEnabled
= false;
491 aItem
.mnSepSize
= nPixSize
;
492 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
493 mpData
->ImplClearLayoutData();
498 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
499 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
502 void ToolBox::InsertBreak( ImplToolItems::size_type nPos
)
504 // create item and add to list
506 aItem
.meType
= ToolBoxItemType::BREAK
;
507 aItem
.mbEnabled
= false;
508 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
509 mpData
->ImplClearLayoutData();
514 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
515 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
518 void ToolBox::RemoveItem( ImplToolItems::size_type nPos
)
520 if( nPos
< mpData
->m_aItems
.size() )
523 bMustCalc
= mpData
->m_aItems
[nPos
].meType
== ToolBoxItemType::BUTTON
;
525 if ( mpData
->m_aItems
[nPos
].mpWindow
)
526 mpData
->m_aItems
[nPos
].mpWindow
->Hide();
528 // add the removed item to PaintRect
529 maPaintRect
.Union( mpData
->m_aItems
[nPos
].maRect
);
531 // ensure not to delete in the Select-Handler
532 if ( mpData
->m_aItems
[nPos
].mnId
== mnCurItemId
)
534 if ( mpData
->m_aItems
[nPos
].mnId
== mnHighItemId
)
537 ImplInvalidate( bMustCalc
);
539 mpData
->m_aItems
.erase( mpData
->m_aItems
.begin()+nPos
);
540 mpData
->ImplClearLayoutData();
543 CallEventListeners( VclEventId::ToolboxItemRemoved
, reinterpret_cast< void* >( nPos
) );
547 void ToolBox::CopyItem( const ToolBox
& rToolBox
, sal_uInt16 nItemId
)
549 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
550 "ToolBox::CopyItem(): ItemId already exists" );
552 ImplToolItems::size_type nPos
= rToolBox
.GetItemPos( nItemId
);
555 if ( nPos
!= ITEM_NOTFOUND
)
557 // push ToolBox item onto the list
558 ImplToolItem aNewItem
= rToolBox
.mpData
->m_aItems
[nPos
];
560 aNewItem
.mpWindow
= nullptr;
561 aNewItem
.mbShowWindow
= false;
563 mpData
->m_aItems
.push_back( aNewItem
);
564 mpData
->ImplClearLayoutData();
569 ImplToolItems::size_type nNewPos2
= mpData
->m_aItems
.size() - 1;
570 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos2
) );
574 void ToolBox::Clear()
576 mpData
->m_aItems
.clear();
577 mpData
->ImplClearLayoutData();
579 // ensure not to delete in the Select-Handler
583 ImplInvalidate( true, true );
586 CallEventListeners( VclEventId::ToolboxAllItemsChanged
);
589 void ToolBox::SetButtonType( ButtonType eNewType
)
591 if ( meButtonType
!= eNewType
)
593 meButtonType
= eNewType
;
595 // better redraw everything, as otherwise there might be problems
596 // with regions that were copied with CopyBits
597 ImplInvalidate( true );
601 void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize
)
603 if( mpData
->meButtonSize
!= eSize
)
605 mpData
->meButtonSize
= eSize
;
611 ToolBoxButtonSize
ToolBox::GetToolboxButtonSize() const
613 return mpData
->meButtonSize
;
616 ImageType
ToolBox::GetImageSize() const
618 ImageType eImageType
= ImageType::Size16
;
619 if (mpData
->meButtonSize
== ToolBoxButtonSize::Large
)
620 eImageType
= ImageType::Size26
;
621 else if (mpData
->meButtonSize
== ToolBoxButtonSize::Size32
)
622 eImageType
= ImageType::Size32
;
627 /*static*/ Size
ToolBox::GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize
)
629 OutputDevice
*pDefault
= Application::GetDefaultDevice();
630 float fScaleFactor
= pDefault
? pDefault
->GetDPIScaleFactor() : 1.0;
632 Size
aUnscaledSize(16, 16);
634 if (eToolBoxButtonSize
== ToolBoxButtonSize::Large
)
636 OUString iconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
637 aUnscaledSize
= vcl::IconThemeInfo::SizeByThemeName(iconTheme
);
639 else if (eToolBoxButtonSize
== ToolBoxButtonSize::Size32
)
641 aUnscaledSize
= Size(32, 32);
643 return Size(aUnscaledSize
.Width() * fScaleFactor
,
644 aUnscaledSize
.Height() * fScaleFactor
);
647 Size
ToolBox::GetDefaultImageSize() const
649 return GetDefaultImageSize(GetToolboxButtonSize());
652 void ToolBox::SetAlign( WindowAlign eNewAlign
)
654 if ( meAlign
!= eNewAlign
)
658 if ( !ImplIsFloatingMode() )
660 // set horizontal/vertical alignment
661 if ( (eNewAlign
== WindowAlign::Left
) || (eNewAlign
== WindowAlign::Right
) )
666 // Update the background according to Persona if necessary
667 ImplInitSettings( false, false, true );
669 // redraw everything, as the border has changed
672 if ( IsReallyVisible() && IsUpdateMode() )
678 void ToolBox::SetLineCount( ImplToolItems::size_type nNewLines
)
683 if ( mnLines
!= nNewLines
)
687 // better redraw everything, as otherwise there might be problems
688 // with regions that were copied with CopyBits
693 ToolBox::ImplToolItems::size_type
ToolBox::GetItemCount() const
695 return mpData
? mpData
->m_aItems
.size() : 0;
698 ToolBoxItemType
ToolBox::GetItemType( ImplToolItems::size_type nPos
) const
700 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].meType
: ToolBoxItemType::DONTKNOW
;
703 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( sal_uInt16 nItemId
) const
707 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
708 for( ImplToolItems::size_type nPos
= 0; nPos
< nCount
; nPos
++ )
709 if( mpData
->m_aItems
[nPos
].mnId
== nItemId
)
712 return ITEM_NOTFOUND
;
715 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( const Point
& rPos
) const
717 // search the item position on the given point
718 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
719 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.IsInside( rPos
); });
721 if( it
!= mpData
->m_aItems
.end() )
722 return std::distance(mpData
->m_aItems
.begin(), it
);
724 return ITEM_NOTFOUND
;
727 sal_uInt16
ToolBox::GetItemId( ImplToolItems::size_type nPos
) const
729 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].mnId
: 0;
732 sal_uInt16
ToolBox::GetItemId( const Point
& rPos
) const
734 // find item that was clicked
735 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
736 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.IsInside( rPos
); });
738 if( (it
!= mpData
->m_aItems
.end()) && (it
->meType
== ToolBoxItemType::BUTTON
) )
744 Size
ToolBox::GetItemContentSize( sal_uInt16 nItemId
)
746 if ( mbCalc
|| mbFormat
)
749 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
750 if ( nPos
< mpData
->m_aItems
.size() )
751 return mpData
->m_aItems
[nPos
].maContentSize
;
756 sal_uInt16
ToolBox::GetItemId(const OUString
&rCommand
) const
761 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
762 [&rCommand
](const ImplToolItem
& rItem
) { return rItem
.maCommandStr
== rCommand
; });
763 if (it
!= mpData
->m_aItems
.end())
769 Point
ToolBox::ImplGetPopupPosition( const tools::Rectangle
& rRect
) const
772 if( !rRect
.IsEmpty() )
774 tools::Rectangle aScreen
= GetDesktopRectPixel();
776 // the popup should be positioned so that it will not cover
777 // the item rect and that it fits the desktop
778 // the preferred direction is always towards the center of
779 // the application window
781 Point devPos
; // the position in device coordinates for screen comparison
784 case WindowAlign::Top
:
785 aPos
= rRect
.BottomLeft();
787 devPos
= OutputToAbsoluteScreenPixel( aPos
);
788 if( devPos
.Y() >= aScreen
.Bottom() )
789 aPos
.setY( rRect
.Top() );
791 case WindowAlign::Bottom
:
792 aPos
= rRect
.TopLeft();
794 devPos
= OutputToAbsoluteScreenPixel( aPos
);
795 if( devPos
.Y() <= aScreen
.Top() )
796 aPos
.setY( rRect
.Bottom() );
798 case WindowAlign::Left
:
799 aPos
= rRect
.TopRight();
801 devPos
= OutputToAbsoluteScreenPixel( aPos
);
802 if( devPos
.X() >= aScreen
.Right() )
803 aPos
.setX( rRect
.Left() );
805 case WindowAlign::Right
:
806 aPos
= rRect
.TopLeft();
808 devPos
= OutputToAbsoluteScreenPixel( aPos
);
809 if( devPos
.X() <= aScreen
.Left() )
810 aPos
.setX( rRect
.Right() );
819 tools::Rectangle
ToolBox::GetItemRect( sal_uInt16 nItemId
)
821 if ( mbCalc
|| mbFormat
)
824 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
825 return GetItemPosRect( nPos
);
828 tools::Rectangle
ToolBox::GetItemPosRect( ImplToolItems::size_type nPos
)
830 if ( mbCalc
|| mbFormat
)
833 if ( nPos
< mpData
->m_aItems
.size() )
834 return mpData
->m_aItems
[nPos
].maRect
;
836 return tools::Rectangle();
839 tools::Rectangle
const & ToolBox::GetOverflowRect() const
841 return mpData
->maMenubuttonItem
.maRect
;
844 bool ToolBox::ImplHasExternalMenubutton()
846 // check if the borderwindow (i.e. the decoration) provides the menu button
848 if( ImplIsFloatingMode() )
850 // custom menu is placed in the decoration
851 ImplBorderWindow
*pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
852 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
858 void ToolBox::SetItemBits( sal_uInt16 nItemId
, ToolBoxItemBits nBits
)
860 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
862 if ( nPos
< GetItemCount() )
864 ToolBoxItemBits nOldBits
= mpData
->m_aItems
[nPos
].mnBits
;
865 mpData
->m_aItems
[nPos
].mnBits
= nBits
;
866 nBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
867 nOldBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
868 // trigger reformat when the item width has changed (dropdown arrow)
869 bool bFormat
= ToolBoxItemBits(nBits
& ToolBoxItemBits::DROPDOWN
) != ToolBoxItemBits(nOldBits
& ToolBoxItemBits::DROPDOWN
);
870 if ( nBits
!= nOldBits
)
871 ImplInvalidate( true, bFormat
);
875 ToolBoxItemBits
ToolBox::GetItemBits( sal_uInt16 nItemId
) const
877 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
880 return pItem
->mnBits
;
882 return ToolBoxItemBits::NONE
;
885 void ToolBox::SetItemExpand( sal_uInt16 nItemId
, bool bExpand
)
887 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
891 if (pItem
->mbExpand
!= bExpand
)
893 pItem
->mbExpand
= bExpand
;
894 ImplInvalidate(true, true);
898 void ToolBox::SetItemData( sal_uInt16 nItemId
, void* pNewData
)
900 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
902 if ( nPos
< mpData
->m_aItems
.size() )
904 mpData
->m_aItems
[nPos
].mpUserData
= pNewData
;
905 ImplUpdateItem( nPos
);
909 void* ToolBox::GetItemData( sal_uInt16 nItemId
) const
911 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
914 return pItem
->mpUserData
;
919 void ToolBox::SetItemImage( sal_uInt16 nItemId
, const Image
& rImage
)
921 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
923 if ( nPos
!= ITEM_NOTFOUND
)
925 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
926 Size aOldSize
= pItem
->maImage
.GetSizePixel();
928 pItem
->maImage
= rImage
;
930 // only once all is calculated, do extra work
933 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
934 ImplInvalidate( true );
936 ImplUpdateItem( nPos
);
941 void ToolBox::SetItemOverlayImage( sal_uInt16 nItemId
, const Image
& rImage
)
943 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
945 if ( nPos
!= ITEM_NOTFOUND
)
947 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
948 Size aOldSize
= pItem
->maOverlayImage
.GetSizePixel();
950 pItem
->maOverlayImage
= rImage
;
952 // only once all is calculated, do extra work
955 if (aOldSize
!= pItem
->maOverlayImage
.GetSizePixel())
956 ImplInvalidate( true );
958 ImplUpdateItem( nPos
);
963 static Image
ImplRotImage( const Image
& rImage
, long nAngle10
)
965 BitmapEx
aRotBitmapEx( rImage
.GetBitmapEx() );
967 aRotBitmapEx
.Rotate( nAngle10
, COL_WHITE
);
969 return Image( aRotBitmapEx
);
972 void ToolBox::SetItemImageAngle( sal_uInt16 nItemId
, long nAngle10
)
974 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
976 if ( nPos
!= ITEM_NOTFOUND
)
978 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
979 Size aOldSize
= pItem
->maImage
.GetSizePixel();
981 long nDeltaAngle
= (nAngle10
- pItem
->mnImageAngle
) % 3600;
982 while( nDeltaAngle
< 0 )
985 pItem
->mnImageAngle
= nAngle10
;
986 if( nDeltaAngle
&& !!pItem
->maImage
)
988 pItem
->maImage
= ImplRotImage( pItem
->maImage
, nDeltaAngle
);
993 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
994 ImplInvalidate(true);
996 ImplUpdateItem(nPos
);
1001 static Image
ImplMirrorImage( const Image
& rImage
)
1003 BitmapEx
aMirrBitmapEx( rImage
.GetBitmapEx() );
1005 aMirrBitmapEx
.Mirror( BmpMirrorFlags::Horizontal
);
1007 return Image( aMirrBitmapEx
);
1010 void ToolBox::SetItemImageMirrorMode( sal_uInt16 nItemId
, bool bMirror
)
1012 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1014 if ( nPos
!= ITEM_NOTFOUND
)
1016 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1018 if (pItem
->mbMirrorMode
!= bMirror
)
1020 pItem
->mbMirrorMode
= bMirror
;
1021 if (!!pItem
->maImage
)
1023 pItem
->maImage
= ImplMirrorImage(pItem
->maImage
);
1027 ImplUpdateItem(nPos
);
1032 Image
ToolBox::GetItemImage(sal_uInt16 nItemId
) const
1034 ImplToolItem
* pItem
= ImplGetItem(nItemId
);
1035 return pItem
? pItem
->maImage
: Image();
1038 void ToolBox::SetItemText( sal_uInt16 nItemId
, const OUString
& rText
)
1040 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1042 if ( nPos
!= ITEM_NOTFOUND
)
1044 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1045 // only once all is calculated, do extra work
1047 ((meButtonType
!= ButtonType::SYMBOLONLY
) || !pItem
->maImage
) )
1049 long nOldWidth
= GetCtrlTextWidth( pItem
->maText
);
1050 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1051 mpData
->ImplClearLayoutData();
1052 if ( nOldWidth
!= GetCtrlTextWidth( pItem
->maText
) )
1053 ImplInvalidate( true );
1055 ImplUpdateItem( nPos
);
1058 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1060 // Notify button changed event to prepare accessibility bridge
1061 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1064 CallEventListeners( VclEventId::ToolboxItemTextChanged
, reinterpret_cast< void* >( nPos
) );
1068 const OUString
& ToolBox::GetItemText( sal_uInt16 nItemId
) const
1071 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1075 return pItem
->maText
;
1078 void ToolBox::SetItemWindow( sal_uInt16 nItemId
, vcl::Window
* pNewWindow
)
1080 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1082 if ( nPos
!= ITEM_NOTFOUND
)
1084 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1085 pItem
->mpWindow
= pNewWindow
;
1088 ImplInvalidate( true );
1089 CallEventListeners( VclEventId::ToolboxItemWindowChanged
, reinterpret_cast< void* >( nPos
) );
1093 vcl::Window
* ToolBox::GetItemWindow( sal_uInt16 nItemId
) const
1095 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1098 return pItem
->mpWindow
;
1103 void ToolBox::StartSelection()
1111 mnCurPos
= ITEM_NOTFOUND
;
1117 void ToolBox::EndSelection()
1119 if ( mbDrag
|| mbSelection
)
1123 mbSelection
= false;
1124 if (mnCurPos
!= ITEM_NOTFOUND
)
1125 InvalidateItem(mnCurPos
);
1127 if (IsMouseCaptured())
1132 mnCurPos
= ITEM_NOTFOUND
;
1135 mnMouseModifier
= 0;
1138 void ToolBox::SetItemDown( sal_uInt16 nItemId
, bool bDown
)
1140 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1142 if ( nPos
!= ITEM_NOTFOUND
)
1146 if ( nPos
!= mnCurPos
)
1149 InvalidateItem(mnCurPos
);
1155 if ( nPos
== mnCurPos
)
1157 InvalidateItem(mnCurPos
);
1159 mnCurPos
= ITEM_NOTFOUND
;
1163 if ( mbDrag
|| mbSelection
)
1166 mbSelection
= false;
1168 if (IsMouseCaptured())
1175 mnMouseModifier
= 0;
1179 void ToolBox::SetItemState( sal_uInt16 nItemId
, TriState eState
)
1181 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1183 if ( nPos
!= ITEM_NOTFOUND
)
1185 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1187 // the state has changed
1188 if ( pItem
->meState
!= eState
)
1190 // if RadioCheck, un-check the previous
1191 if ( (eState
== TRISTATE_TRUE
) && (pItem
->mnBits
& ToolBoxItemBits::AUTOCHECK
) &&
1192 (pItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
) )
1194 ImplToolItem
* pGroupItem
;
1195 ImplToolItems::size_type nGroupPos
;
1196 ImplToolItems::size_type nItemCount
= GetItemCount();
1201 pGroupItem
= &mpData
->m_aItems
[nGroupPos
-1];
1202 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1204 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1205 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1213 while ( nGroupPos
< nItemCount
)
1215 pGroupItem
= &mpData
->m_aItems
[nGroupPos
];
1216 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1218 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1219 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1227 pItem
->meState
= eState
;
1228 ImplUpdateItem( nPos
);
1230 // Notify button changed event to prepare accessibility bridge
1231 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1233 // Call accessible listener to notify state_changed event
1234 CallEventListeners( VclEventId::ToolboxItemUpdated
, reinterpret_cast< void* >(nPos
) );
1239 TriState
ToolBox::GetItemState( sal_uInt16 nItemId
) const
1241 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1244 return pItem
->meState
;
1246 return TRISTATE_FALSE
;
1249 void ToolBox::EnableItem( sal_uInt16 nItemId
, bool bEnable
)
1251 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1253 if ( nPos
!= ITEM_NOTFOUND
)
1255 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1256 if ( pItem
->mbEnabled
!= bEnable
)
1258 pItem
->mbEnabled
= bEnable
;
1260 // if existing, also redraw the window
1261 if ( pItem
->mpWindow
)
1262 pItem
->mpWindow
->Enable( pItem
->mbEnabled
);
1265 ImplUpdateItem( nPos
);
1267 ImplUpdateInputEnable();
1269 // Notify button changed event to prepare accessibility bridge
1270 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1272 CallEventListeners( bEnable
? VclEventId::ToolboxItemEnabled
: VclEventId::ToolboxItemDisabled
, reinterpret_cast< void* >( nPos
) );
1277 bool ToolBox::IsItemEnabled( sal_uInt16 nItemId
) const
1279 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1282 return pItem
->mbEnabled
;
1287 void ToolBox::ShowItem( sal_uInt16 nItemId
, bool bVisible
)
1289 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1290 mpData
->ImplClearLayoutData();
1292 if ( nPos
!= ITEM_NOTFOUND
)
1294 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1295 if ( pItem
->mbVisible
!= bVisible
)
1297 pItem
->mbVisible
= bVisible
;
1303 bool ToolBox::IsItemClipped( sal_uInt16 nItemId
) const
1305 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1308 return pItem
->IsClipped();
1313 bool ToolBox::IsItemVisible( sal_uInt16 nItemId
) const
1315 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1318 return pItem
->mbVisible
;
1323 bool ToolBox::IsItemReallyVisible( sal_uInt16 nItemId
) const
1325 // is the item on the visible area of the toolbox?
1327 tools::Rectangle
aRect( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
, mnDY
-mnBottomBorder
);
1328 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1330 if ( pItem
&& pItem
->mbVisible
&&
1331 !pItem
->maRect
.IsEmpty() && aRect
.IsOver( pItem
->maRect
) )
1339 void ToolBox::SetItemCommand(sal_uInt16 nItemId
, const OUString
& rCommand
)
1341 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1344 pItem
->maCommandStr
= rCommand
;
1347 OUString
ToolBox::GetItemCommand( sal_uInt16 nItemId
) const
1349 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1352 return pItem
->maCommandStr
;
1357 void ToolBox::SetQuickHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1359 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1362 pItem
->maQuickHelpText
= rText
;
1365 OUString
ToolBox::GetQuickHelpText( sal_uInt16 nItemId
) const
1367 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1370 return pItem
->maQuickHelpText
;
1375 void ToolBox::SetHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1377 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1380 pItem
->maHelpText
= rText
;
1383 const OUString
& ToolBox::GetHelpText( sal_uInt16 nItemId
) const
1385 return ImplGetHelpText( nItemId
);
1388 void ToolBox::SetHelpId( sal_uInt16 nItemId
, const OString
& rHelpId
)
1390 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1393 pItem
->maHelpId
= rHelpId
;
1396 void ToolBox::SetOutStyle( sal_uInt16 nNewStyle
)
1398 // always force flat looking toolbars since NWF
1399 nNewStyle
|= TOOLBOX_STYLE_FLAT
;
1401 if ( mnOutStyle
!= nNewStyle
)
1403 mnOutStyle
= nNewStyle
;
1404 ImplDisableFlatButtons();
1406 // so as to redo the ButtonDevice
1407 if ( !(mnOutStyle
& TOOLBOX_STYLE_FLAT
) )
1410 mnMaxItemHeight
= 1;
1413 ImplInvalidate( true, true );
1417 // disable key input if all items are disabled
1418 void ToolBox::ImplUpdateInputEnable()
1420 mpData
->mbKeyInputDisabled
= std::none_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1421 [](const ImplToolItem
& rItem
) {
1422 // at least one useful entry
1423 return rItem
.mbEnabled
;
1427 void ToolBox::ImplFillLayoutData()
1429 mpData
->m_pLayoutData
.reset(new ToolBoxLayoutData
);
1431 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
1432 for( ImplToolItems::size_type i
= 0; i
< nCount
; i
++ )
1434 ImplToolItem
* pItem
= &mpData
->m_aItems
[i
];
1436 // only draw, if the rectangle is within PaintRectangle
1437 if (!pItem
->maRect
.IsEmpty())
1442 OUString
ToolBox::GetDisplayText() const
1444 if( ! mpData
->m_pLayoutData
)
1445 const_cast<ToolBox
*>(this)->ImplFillLayoutData();
1446 return mpData
->m_pLayoutData
? mpData
->m_pLayoutData
->m_aDisplayText
: OUString();
1449 tools::Rectangle
ToolBox::GetCharacterBounds( sal_uInt16 nItemID
, long nIndex
)
1451 long nItemIndex
= -1;
1452 if( ! mpData
->m_pLayoutData
)
1453 ImplFillLayoutData();
1454 if( mpData
->m_pLayoutData
)
1456 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineItemIds
.size(); i
++ )
1458 if( mpData
->m_pLayoutData
->m_aLineItemIds
[i
] == nItemID
)
1460 nItemIndex
= mpData
->m_pLayoutData
->m_aLineIndices
[i
];
1465 return (mpData
->m_pLayoutData
&& nItemIndex
!= -1) ? mpData
->m_pLayoutData
->GetCharacterBounds( nItemIndex
+nIndex
) : tools::Rectangle();
1468 long ToolBox::GetIndexForPoint( const Point
& rPoint
, sal_uInt16
& rItemID
)
1472 if( ! mpData
->m_pLayoutData
)
1473 ImplFillLayoutData();
1474 if( mpData
->m_pLayoutData
)
1476 nIndex
= mpData
->m_pLayoutData
->GetIndexForPoint( rPoint
);
1477 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineIndices
.size(); i
++ )
1479 if( mpData
->m_pLayoutData
->m_aLineIndices
[i
] <= nIndex
&&
1480 (i
== mpData
->m_pLayoutData
->m_aLineIndices
.size()-1 || mpData
->m_pLayoutData
->m_aLineIndices
[i
+1] > nIndex
) )
1482 rItemID
= mpData
->m_pLayoutData
->m_aLineItemIds
[i
];
1490 void ToolBox::SetDropdownClickHdl( const Link
<ToolBox
*, void>& rLink
)
1492 if (mpData
!= nullptr) {
1493 mpData
->maDropdownClickHdl
= rLink
;
1497 void ToolBox::SetMenuType( ToolBoxMenuType aType
)
1499 if( aType
!= mpData
->maMenuType
)
1501 mpData
->maMenuType
= aType
;
1502 if( IsFloatingMode() )
1504 // the menu button may have to be moved into the decoration which changes the layout
1505 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1507 pWrapper
->ShowTitleButton( TitleButton::Menu
, bool( aType
& ToolBoxMenuType::Customize
) );
1511 ImplSetMinMaxFloatSize();
1515 // trigger redraw of menu button
1516 if( !mpData
->maMenubuttonItem
.maRect
.IsEmpty() )
1517 Invalidate(mpData
->maMenubuttonItem
.maRect
);
1522 ToolBoxMenuType
ToolBox::GetMenuType() const
1524 return mpData
->maMenuType
;
1527 bool ToolBox::IsMenuEnabled() const
1529 return mpData
->maMenuType
!= ToolBoxMenuType::NONE
;
1532 PopupMenu
* ToolBox::GetMenu() const
1534 return mpData
== nullptr ? nullptr : mpData
->mpMenu
;
1537 void ToolBox::SetMenuExecuteHdl( const Link
<ToolBox
*, void>& rLink
)
1539 mpData
->maMenuButtonHdl
= rLink
;
1542 bool ToolBox::ImplHasClippedItems()
1544 // are any items currently clipped ?
1546 return std::any_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1547 [](const ImplToolItem
& rItem
) { return rItem
.IsClipped(); });
1552 MenuItemBits
ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits
)
1554 MenuItemBits nMenuItemBits
= MenuItemBits::NONE
;
1555 if ((nToolItemBits
& ToolBoxItemBits::CHECKABLE
) ||
1556 (nToolItemBits
& ToolBoxItemBits::DROPDOWN
))
1558 nMenuItemBits
|= MenuItemBits::CHECKABLE
;
1560 return nMenuItemBits
;
1564 void ToolBox::UpdateCustomMenu()
1566 // fill clipped items into menu
1567 PopupMenu
*pMenu
= GetMenu();
1570 // add menu items: first the overflow items, then hidden items, both in the
1571 // order they would usually appear in the toolbar. Separators that would be
1572 // in the toolbar are ignored as they would introduce too much clutter,
1573 // instead we have a single separator to help distinguish between overflow
1574 // and hidden items.
1575 if ( !mpData
->m_aItems
.empty() )
1577 // nStartPos will hold the number of clipped items appended from first loop
1578 for ( const auto& rItem
: mpData
->m_aItems
)
1580 if( rItem
.IsClipped() )
1582 sal_uInt16 id
= rItem
.mnId
+ TOOLBOX_MENUITEM_START
;
1583 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1584 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1585 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1586 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1587 pMenu
->CheckItem ( id
, rItem
.meState
== TRISTATE_TRUE
);
1591 // add a separator below the inserted clipped-items
1592 pMenu
->InsertSeparator();
1594 // now append the items that are explicitly disabled
1595 for ( const auto& rItem
: mpData
->m_aItems
)
1597 if( rItem
.IsItemHidden() )
1599 sal_uInt16 id
= rItem
.mnId
+ TOOLBOX_MENUITEM_START
;
1600 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1601 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1602 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1603 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1604 pMenu
->CheckItem( id
, rItem
.meState
== TRISTATE_TRUE
);
1611 IMPL_LINK( ToolBox
, ImplCustomMenuListener
, VclMenuEvent
&, rEvent
, void )
1613 if( rEvent
.GetMenu() == GetMenu() && rEvent
.GetId() == VclEventId::MenuSelect
)
1615 sal_uInt16 id
= GetMenu()->GetItemId( rEvent
.GetItemPos() );
1616 if( id
>= TOOLBOX_MENUITEM_START
)
1617 TriggerItem( id
- TOOLBOX_MENUITEM_START
);
1621 void ToolBox::ExecuteCustomMenu( const tools::Rectangle
& rRect
)
1623 if ( !IsMenuEnabled() || ImplIsInPopupMode() )
1628 if( GetMenuType() & ToolBoxMenuType::Customize
)
1629 // call button handler to allow for menu customization
1630 mpData
->maMenuButtonHdl
.Call( this );
1632 GetMenu()->AddEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1634 // make sure all disabled entries will be shown
1635 GetMenu()->SetMenuFlags(
1636 GetMenu()->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries
);
1638 // toolbox might be destroyed during execute
1639 bool bBorderDel
= false;
1641 VclPtr
<vcl::Window
> pWin
= this;
1642 tools::Rectangle aMenuRect
= rRect
;
1643 VclPtr
<ImplBorderWindow
> pBorderWin
;
1644 if( aMenuRect
.IsEmpty() && IsFloatingMode() )
1646 // custom menu is placed in the decoration
1647 pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
1648 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
1651 aMenuRect
= pBorderWin
->GetMenuRect();
1656 sal_uInt16 uId
= GetMenu()->Execute( pWin
, tools::Rectangle( ImplGetPopupPosition( aMenuRect
), Size() ),
1657 PopupMenuFlags::ExecuteDown
| PopupMenuFlags::NoMouseUpClose
);
1659 if ( pWin
->IsDisposed() )
1663 GetMenu()->RemoveEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1666 if( pBorderWin
->IsDisposed() )
1670 pWin
->Invalidate( aMenuRect
);
1673 GrabFocusToDocument();
1676 // checks override first, useful during calculation of sizes
1677 bool ToolBox::ImplIsFloatingMode() const
1679 SAL_WARN_IF( mpData
->mbAssumeDocked
&& mpData
->mbAssumeFloating
, "vcl",
1680 "cannot assume docked and floating" );
1682 if( mpData
->mbAssumeDocked
)
1684 else if( mpData
->mbAssumeFloating
)
1687 return IsFloatingMode();
1690 // checks override first, useful during calculation of sizes
1691 bool ToolBox::ImplIsInPopupMode() const
1693 if( mpData
->mbAssumePopupMode
)
1697 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1698 return ( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() );
1702 void ToolBox::Lock( bool bLock
)
1704 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1707 if( mpData
->mbIsLocked
!= bLock
)
1709 mpData
->mbIsLocked
= bLock
;
1710 if( !ImplIsFloatingMode() )
1714 SetSizePixel( CalcWindowSizePixel(1) );
1720 bool ToolBox::AlwaysLocked()
1722 // read config item to determine toolbox behaviour, used for subtoolbars
1724 static int nAlwaysLocked
= -1;
1726 if( nAlwaysLocked
== -1 )
1728 nAlwaysLocked
= 0; // ask configuration only once
1730 utl::OConfigurationNode aNode
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1731 comphelper::getProcessComponentContext(),
1732 "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ); // note: case sensitive !
1733 if ( aNode
.isValid() )
1735 // feature enabled ?
1736 bool bStatesEnabled
= bool();
1737 css::uno::Any aValue
= aNode
.getNodeValue( "StatesEnabled" );
1738 if( aValue
>>= bStatesEnabled
)
1740 if( bStatesEnabled
)
1742 // now read the locking state
1743 utl::OConfigurationNode aNode2
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1744 comphelper::getProcessComponentContext(),
1745 "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ); // note: case sensitive !
1747 bool bLocked
= bool();
1748 css::uno::Any aValue2
= aNode2
.getNodeValue( "Locked" );
1749 if( aValue2
>>= bLocked
)
1750 nAlwaysLocked
= bLocked
? 1 : 0;
1756 return nAlwaysLocked
== 1;
1759 bool ToolBox::WillUsePopupMode() const
1761 return mpData
->mbWillUsePopupMode
;
1764 void ToolBox::WillUsePopupMode( bool b
)
1766 mpData
->mbWillUsePopupMode
= b
;
1769 boost::property_tree::ptree
ToolBox::DumpAsPropertyTree()
1771 boost::property_tree::ptree
aTree(DockingWindow::DumpAsPropertyTree());
1772 boost::property_tree::ptree aChildren
;
1774 boost::property_tree::ptree::const_assoc_iterator found
= aTree
.find("children");
1775 if (found
== aTree
.not_found())
1777 for (ToolBox::ImplToolItems::size_type i
= 0; i
< GetItemCount(); ++i
)
1779 ToolBoxItemType type
= GetItemType(i
);
1780 if (type
== ToolBoxItemType::BUTTON
)
1782 boost::property_tree::ptree aEntry
;
1783 int nId
= GetItemId(i
);
1784 aEntry
.put("type", "toolitem");
1785 aEntry
.put("text", GetItemText(nId
));
1786 aEntry
.put("command", GetItemCommand(nId
));
1787 aChildren
.push_back(std::make_pair("", aEntry
));
1791 aTree
.add_child("children", aChildren
);
1797 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */