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"
22 #include <comphelper/processfactory.hxx>
23 #include <tools/debug.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/idle.hxx>
28 #include <vcl/help.hxx>
29 #include <vcl/bitmap.hxx>
30 #include <vcl/toolbox.hxx>
31 #include <vcl/mnemonic.hxx>
32 #include <vcl/menu.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/IconThemeInfo.hxx>
35 #include <vcl/commandinfoprovider.hxx>
41 #include <unotools/confignode.hxx>
45 #define TB_SEP_SIZE 8 // Separator size
48 ImplToolBoxPrivateData::ImplToolBoxPrivateData() :
49 m_pLayoutData( nullptr )
51 meButtonSize
= ToolBoxButtonSize::DontCare
;
52 mpMenu
= VclPtr
<PopupMenu
>::Create();
55 maMenuType
= ToolBoxMenuType::NONE
;
56 maMenubuttonItem
.maItemSize
= Size( TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
, TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
);
57 maMenubuttonItem
.meState
= TRISTATE_FALSE
;
58 mnMenuButtonWidth
= TB_MENUBUTTON_SIZE
;
61 mbNativeButtons
= false;
62 mbIsPaintLocked
= false;
63 mbAssumeDocked
= false;
64 mbAssumePopupMode
= false;
65 mbAssumeFloating
= false;
66 mbKeyInputDisabled
= false;
67 mbMenubuttonSelected
= false;
69 mbWillUsePopupMode
= false;
70 mbDropDownByKeyboard
= false;
73 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
76 mpMenu
.disposeAndClear();
79 void ImplToolItem::init(sal_uInt16 nItemId
, ToolBoxItemBits nItemBits
,
85 meType
= ToolBoxItemType::BUTTON
;
87 meState
= TRISTATE_FALSE
;
90 mbEmptyBtn
= bEmptyBtn
;
93 mnSepSize
= TB_SEP_SIZE
;
94 mnDropDownArrowWidth
= TB_DROPDOWNARROWWIDTH
;
97 mbVisibleText
= false;
101 ImplToolItem::ImplToolItem()
103 init(0, ToolBoxItemBits::NONE
, true);
106 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
107 ToolBoxItemBits nItemBits
) :
110 init(nItemId
, nItemBits
, false);
113 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const OUString
& rText
,
114 ToolBoxItemBits nItemBits
) :
117 init(nItemId
, nItemBits
, false);
120 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
121 const OUString
& rText
, ToolBoxItemBits nItemBits
) :
125 init(nItemId
, nItemBits
, false);
128 Size
ImplToolItem::GetSize( bool bHorz
, bool bCheckMaxWidth
, long maxWidth
, const Size
& rDefaultSize
)
130 Size
aSize( rDefaultSize
); // the size of 'standard' toolbox items
131 // non-standard items are eg windows or buttons with text
133 if ( (meType
== ToolBoxItemType::BUTTON
) || (meType
== ToolBoxItemType::SPACE
) )
137 if ( mpWindow
&& bHorz
)
139 // get size of item window and check if it fits
140 // no windows in vertical toolbars (the default is mbShowWindow=false)
141 Size aWinSize
= mpWindow
->GetSizePixel();
143 if (mpWindow
->GetStyle() & WB_NOLABEL
)
144 // Window wants no label? Then don't check width, it'll be just
146 bCheckMaxWidth
= false;
148 if ( !bCheckMaxWidth
|| (aWinSize
.Width() <= maxWidth
) )
150 aSize
.Width() = aWinSize
.Width();
151 aSize
.Height() = aWinSize
.Height();
164 else if ( meType
== ToolBoxItemType::SEPARATOR
)
168 aSize
.Width() = mnSepSize
;
169 aSize
.Height() = rDefaultSize
.Height();
173 aSize
.Width() = rDefaultSize
.Width();
174 aSize
.Height() = mnSepSize
;
177 else if ( meType
== ToolBoxItemType::BREAK
)
186 void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType
, bool& rbImage
, bool& rbText
) const
188 if ( meType
!= ToolBoxItemType::BUTTON
)
190 // no button -> draw nothing
191 rbImage
= rbText
= false;
198 // check for image and/or text
203 if ( maText
.isEmpty() )
208 // prefer images if symbolonly buttons are drawn
209 // prefer texts if textonly buttons are drawn
211 if ( eButtonType
== ButtonType::SYMBOLONLY
) // drawing icons only
213 if( bHasImage
|| !bHasText
)
224 else if ( eButtonType
== ButtonType::TEXT
) // drawing text only
226 if( bHasText
|| !bHasImage
)
237 else // drawing icons and text both
244 Rectangle
ImplToolItem::GetDropDownRect( bool bHorz
) const
247 if( (mnBits
& ToolBoxItemBits::DROPDOWN
) && !maRect
.IsEmpty() )
250 if( mbVisibleText
&& !bHorz
)
251 // item will be rotated -> place dropdown to the bottom
252 aRect
.Top() = aRect
.Bottom() - mnDropDownArrowWidth
;
254 // place dropdown to the right
255 aRect
.Left() = aRect
.Right() - mnDropDownArrowWidth
;
260 bool ImplToolItem::IsClipped() const
262 return ( meType
== ToolBoxItemType::BUTTON
&& mbVisible
&& maRect
.IsEmpty() );
265 bool ImplToolItem::IsItemHidden() const
267 return ( meType
== ToolBoxItemType::BUTTON
&& !mbVisible
);
270 void ToolBox::ImplInvalidate( bool bNewCalc
, bool bFullPaint
)
272 ImplUpdateInputEnable();
281 // do we need to redraw?
282 if ( IsReallyVisible() && IsUpdateMode() )
284 Invalidate( Rectangle( mnLeftBorder
, mnTopBorder
,
285 mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
295 // do we need to redraw?
296 if ( IsReallyVisible() && IsUpdateMode() )
301 // request new layout by layoutmanager
302 CallEventListeners( VCLEVENT_TOOLBOX_FORMATCHANGED
);
305 void ToolBox::ImplUpdateItem( sal_uInt16 nIndex
)
307 // do we need to redraw?
308 if ( IsReallyVisible() && IsUpdateMode() )
310 if ( nIndex
== 0xFFFF )
312 // #i52217# no immediate draw as this might lead to paint problems
313 Invalidate( Rectangle( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
319 // #i52217# no immediate draw as this might lead to paint problems
320 Invalidate( mpData
->m_aItems
[nIndex
].maRect
);
323 maPaintRect
.Union( mpData
->m_aItems
[nIndex
].maRect
);
328 void ToolBox::Click()
330 CallEventListeners( VCLEVENT_TOOLBOX_CLICK
);
331 maClickHdl
.Call( this );
334 void ToolBox::DoubleClick()
336 CallEventListeners( VCLEVENT_TOOLBOX_DOUBLECLICK
);
337 maDoubleClickHdl
.Call( this );
340 void ToolBox::Activate()
343 CallEventListeners( VCLEVENT_TOOLBOX_ACTIVATE
);
344 maActivateHdl
.Call( this );
347 void ToolBox::Deactivate()
350 CallEventListeners( VCLEVENT_TOOLBOX_DEACTIVATE
);
351 maDeactivateHdl
.Call( this );
354 void ToolBox::Highlight()
356 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT
);
359 void ToolBox::Select()
361 VclPtr
<vcl::Window
> xWindow
= this;
363 CallEventListeners( VCLEVENT_TOOLBOX_SELECT
);
364 maSelectHdl
.Call( this );
366 if ( xWindow
->IsDisposed() )
369 // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
370 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
371 if( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() )
372 pWrapper
->GetFloatingWindow()->EndPopupMode();
375 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, ToolBoxItemBits nBits
, sal_uInt16 nPos
)
377 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
378 SAL_WARN_IF( GetItemPos( nItemId
) != TOOLBOX_ITEM_NOTFOUND
, "vcl",
379 "ToolBox::InsertItem(): ItemId already exists" );
381 // create item and add to list
382 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
383 ImplToolItem( nItemId
, rImage
, nBits
) );
384 SetItemImage(nItemId
, rImage
);
385 mpData
->ImplClearLayoutData();
387 ImplInvalidate( true );
390 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
391 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >(nNewPos
) );
394 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, const OUString
& rText
, ToolBoxItemBits nBits
,
397 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
398 SAL_WARN_IF( GetItemPos( nItemId
) != TOOLBOX_ITEM_NOTFOUND
, "vcl",
399 "ToolBox::InsertItem(): ItemId already exists" );
401 // create item and add to list
402 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
403 ImplToolItem( nItemId
, rImage
, MnemonicGenerator::EraseAllMnemonicChars(rText
), nBits
) );
404 SetItemImage(nItemId
, rImage
);
405 mpData
->ImplClearLayoutData();
407 ImplInvalidate( true );
410 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
411 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
414 void ToolBox::InsertItem( sal_uInt16 nItemId
, const OUString
& rText
, ToolBoxItemBits nBits
, sal_uInt16 nPos
)
416 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
417 SAL_WARN_IF( GetItemPos( nItemId
) != TOOLBOX_ITEM_NOTFOUND
, "vcl",
418 "ToolBox::InsertItem(): ItemId already exists" );
420 // create item and add to list
421 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
422 ImplToolItem( nItemId
, MnemonicGenerator::EraseAllMnemonicChars(rText
), nBits
) );
423 mpData
->ImplClearLayoutData();
425 ImplInvalidate( true );
428 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
429 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
432 void ToolBox::InsertItem(const OUString
& rCommand
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
, ToolBoxItemBits nBits
,
433 const Size
& rRequestedSize
, sal_uInt16 nPos
)
435 OUString
aLabel(vcl::CommandInfoProvider::Instance().GetLabelForCommand(rCommand
, rFrame
));
436 OUString
aTooltip(vcl::CommandInfoProvider::Instance().GetTooltipForCommand(rCommand
, rFrame
));
438 vcl::ImageType eImageType
= vcl::ImageType::Size16
;
440 if (GetToolboxButtonSize() == ToolBoxButtonSize::Large
)
441 eImageType
= vcl::ImageType::Size26
;
442 else if (GetToolboxButtonSize() == ToolBoxButtonSize::Size32
)
443 eImageType
= vcl::ImageType::Size32
;
445 CommandInfoProvider
& rInfoProvider
= vcl::CommandInfoProvider::Instance();
446 Image
aImage(rInfoProvider
.GetImageForCommand(rCommand
, rFrame
, eImageType
));
448 sal_uInt16 nItemId
= GetItemCount() + 1;
449 InsertItem(nItemId
, aImage
, aLabel
, nBits
, nPos
);
450 SetItemCommand(nItemId
, rCommand
);
451 SetQuickHelpText(nItemId
, aTooltip
);
453 // set the minimal size
454 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
456 pItem
->maMinimalItemSize
= rRequestedSize
;
459 void ToolBox::InsertWindow( sal_uInt16 nItemId
, vcl::Window
* pWindow
,
460 ToolBoxItemBits nBits
, sal_uInt16 nPos
)
462 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertWindow(): ItemId == 0" );
463 SAL_WARN_IF( GetItemPos( nItemId
) != TOOLBOX_ITEM_NOTFOUND
, "vcl",
464 "ToolBox::InsertWindow(): ItemId already exists" );
466 // create item and add to list
468 aItem
.mnId
= nItemId
;
469 aItem
.meType
= ToolBoxItemType::BUTTON
;
470 aItem
.mnBits
= nBits
;
471 aItem
.mpWindow
= pWindow
;
472 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
473 mpData
->ImplClearLayoutData();
478 ImplInvalidate( true );
481 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
482 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
485 void ToolBox::InsertSpace()
487 // create item and add to list
489 aItem
.meType
= ToolBoxItemType::SPACE
;
490 aItem
.mbEnabled
= false;
491 mpData
->m_aItems
.push_back( aItem
);
492 mpData
->ImplClearLayoutData();
497 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(mpData
->m_aItems
.size() - 1);
498 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
501 void ToolBox::InsertSeparator( sal_uInt16 nPos
, sal_uInt16 nPixSize
)
503 // create item and add to list
505 aItem
.meType
= ToolBoxItemType::SEPARATOR
;
506 aItem
.mbEnabled
= false;
508 aItem
.mnSepSize
= nPixSize
;
509 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
510 mpData
->ImplClearLayoutData();
515 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
516 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
519 void ToolBox::InsertBreak( sal_uInt16 nPos
)
521 // create item and add to list
523 aItem
.meType
= ToolBoxItemType::BREAK
;
524 aItem
.mbEnabled
= false;
525 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
526 mpData
->ImplClearLayoutData();
531 sal_uInt16 nNewPos
= sal::static_int_cast
<sal_uInt16
>(( nPos
== TOOLBOX_APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
);
532 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos
) );
535 void ToolBox::RemoveItem( sal_uInt16 nPos
)
537 if( nPos
< mpData
->m_aItems
.size() )
540 if ( mpData
->m_aItems
[nPos
].meType
== ToolBoxItemType::BUTTON
)
545 if ( mpData
->m_aItems
[nPos
].mpWindow
)
546 mpData
->m_aItems
[nPos
].mpWindow
->Hide();
548 // add the removed item to PaintRect
549 maPaintRect
.Union( mpData
->m_aItems
[nPos
].maRect
);
551 // ensure not to delete in the Select-Handler
552 if ( mpData
->m_aItems
[nPos
].mnId
== mnCurItemId
)
554 if ( mpData
->m_aItems
[nPos
].mnId
== mnHighItemId
)
557 ImplInvalidate( bMustCalc
);
559 mpData
->m_aItems
.erase( mpData
->m_aItems
.begin()+nPos
);
560 mpData
->ImplClearLayoutData();
563 CallEventListeners( VCLEVENT_TOOLBOX_ITEMREMOVED
, reinterpret_cast< void* >( nPos
) );
567 void ToolBox::CopyItem( const ToolBox
& rToolBox
, sal_uInt16 nItemId
)
569 SAL_WARN_IF( GetItemPos( nItemId
) != TOOLBOX_ITEM_NOTFOUND
, "vcl",
570 "ToolBox::CopyItem(): ItemId already exists" );
572 sal_uInt16 nPos
= rToolBox
.GetItemPos( nItemId
);
575 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
577 // push ToolBox item onto the list
578 ImplToolItem aNewItem
= rToolBox
.mpData
->m_aItems
[nPos
];
580 aNewItem
.mpWindow
= nullptr;
581 aNewItem
.mbShowWindow
= false;
583 mpData
->m_aItems
.push_back( aNewItem
);
584 mpData
->ImplClearLayoutData();
589 sal_uInt16 nNewPos2
= sal::static_int_cast
<sal_uInt16
>(mpData
->m_aItems
.size() - 1);
590 CallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED
, reinterpret_cast< void* >( nNewPos2
) );
594 void ToolBox::Clear()
596 mpData
->m_aItems
.clear();
597 mpData
->ImplClearLayoutData();
599 // ensure not to delete in the Select-Handler
603 ImplInvalidate( true, true );
606 CallEventListeners( VCLEVENT_TOOLBOX_ALLITEMSCHANGED
);
609 void ToolBox::SetButtonType( ButtonType eNewType
)
611 if ( meButtonType
!= eNewType
)
613 meButtonType
= eNewType
;
615 // better redraw everything, as otherwise there might be problems
616 // with regions that were copied with CopyBits
617 ImplInvalidate( true );
621 void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize
)
623 if( mpData
->meButtonSize
!= eSize
)
625 mpData
->meButtonSize
= eSize
;
631 ToolBoxButtonSize
ToolBox::GetToolboxButtonSize() const
633 return mpData
->meButtonSize
;
636 /*static*/ Size
ToolBox::GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize
)
638 OutputDevice
*pDefault
= Application::GetDefaultDevice();
639 float fScaleFactor
= pDefault
? pDefault
->GetDPIScaleFactor() : 1.0;
641 Size aUnscaledSize
= Size(16, 16);
643 if (eToolBoxButtonSize
== ToolBoxButtonSize::Large
)
645 OUString iconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
646 aUnscaledSize
= vcl::IconThemeInfo::SizeByThemeName(iconTheme
);
648 else if (eToolBoxButtonSize
== ToolBoxButtonSize::Size32
)
650 aUnscaledSize
= Size(32, 32);
652 return Size(aUnscaledSize
.Width() * fScaleFactor
,
653 aUnscaledSize
.Height() * fScaleFactor
);
656 Size
ToolBox::GetDefaultImageSize() const
658 return GetDefaultImageSize(GetToolboxButtonSize());
661 void ToolBox::SetAlign( WindowAlign eNewAlign
)
663 if ( meAlign
!= eNewAlign
)
667 if ( !ImplIsFloatingMode() )
669 // set horizontal/vertical alignment
670 if ( (eNewAlign
== WindowAlign::Left
) || (eNewAlign
== WindowAlign::Right
) )
675 // Update the background according to Persona if necessary
676 ImplInitSettings( false, false, true );
678 // redraw everything, as the border has changed
681 if ( IsReallyVisible() && IsUpdateMode() )
687 void ToolBox::SetLineCount( sal_uInt16 nNewLines
)
692 if ( mnLines
!= nNewLines
)
696 // better redraw everything, as otherwise there might be problems
697 // with regions that were copied with CopyBits
702 void ToolBox::SetPageScroll( bool b
)
704 mpData
->mbPageScroll
= b
;
707 sal_uInt16
ToolBox::GetItemCount() const
709 return mpData
? (sal_uInt16
)mpData
->m_aItems
.size() : 0;
712 ToolBoxItemType
ToolBox::GetItemType( sal_uInt16 nPos
) const
714 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].meType
: ToolBoxItemType::DONTKNOW
;
717 sal_uInt16
ToolBox::GetItemPos( sal_uInt16 nItemId
) const
721 int nCount
= mpData
->m_aItems
.size();
722 for( int nPos
= 0; nPos
< nCount
; nPos
++ )
723 if( mpData
->m_aItems
[nPos
].mnId
== nItemId
)
724 return (sal_uInt16
)nPos
;
726 return TOOLBOX_ITEM_NOTFOUND
;
729 sal_uInt16
ToolBox::GetItemPos( const Point
& rPos
) const
731 // search the item position on the given point
732 sal_uInt16 nRet
= TOOLBOX_ITEM_NOTFOUND
;
734 std::vector
< ImplToolItem
>::const_iterator it
= mpData
->m_aItems
.begin();
735 while( it
!= mpData
->m_aItems
.end() )
737 if ( it
->maRect
.IsInside( rPos
) )
739 // item found -> save position and break
751 sal_uInt16
ToolBox::GetItemId( sal_uInt16 nPos
) const
753 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].mnId
: 0;
756 sal_uInt16
ToolBox::GetItemId( const Point
& rPos
) const
758 // find item that was clicked
759 std::vector
< ImplToolItem
>::const_iterator it
= mpData
->m_aItems
.begin();
760 while( it
!= mpData
->m_aItems
.end() )
763 if ( it
->maRect
.IsInside( rPos
) )
765 if ( it
->meType
== ToolBoxItemType::BUTTON
)
777 Size
ToolBox::GetItemContentSize( sal_uInt16 nItemId
) const
779 if ( mbCalc
|| mbFormat
)
780 (const_cast<ToolBox
*>(this))->ImplFormat();
782 sal_uInt16 nPos
= GetItemPos( nItemId
);
783 if ( nPos
< mpData
->m_aItems
.size() )
784 return mpData
->m_aItems
[nPos
].maContentSize
;
789 sal_uInt16
ToolBox::GetItemId(const OUString
&rCommand
) const
792 return TOOLBOX_ITEM_NOTFOUND
;
794 for (std::vector
<ImplToolItem
>::const_iterator it
= mpData
->m_aItems
.begin(); it
!= mpData
->m_aItems
.end(); ++it
)
796 if (it
->maCommandStr
== rCommand
)
803 Point
ToolBox::ImplGetPopupPosition( const Rectangle
& rRect
, const Size
& rSize
) const
806 if( !rRect
.IsEmpty() )
808 Rectangle aScreen
= GetDesktopRectPixel();
810 // the popup should be positioned so that it will not cover
811 // the item rect and that it fits the desktop
812 // the preferred direction is always towards the center of
813 // the application window
815 Point devPos
; // the position in device coordinates for screen comparison
818 case WindowAlign::Top
:
819 aPos
= rRect
.BottomLeft();
821 devPos
= OutputToAbsoluteScreenPixel( aPos
);
822 if( devPos
.Y() + rSize
.Height() >= aScreen
.Bottom() )
823 aPos
.Y() = rRect
.Top() - rSize
.Height();
825 case WindowAlign::Bottom
:
826 aPos
= rRect
.TopLeft();
828 devPos
= OutputToAbsoluteScreenPixel( aPos
);
829 if( devPos
.Y() - rSize
.Height() > aScreen
.Top() )
830 aPos
.Y() -= rSize
.Height();
832 aPos
.Y() = rRect
.Bottom();
834 case WindowAlign::Left
:
835 aPos
= rRect
.TopRight();
837 devPos
= OutputToAbsoluteScreenPixel( aPos
);
838 if( devPos
.X() + rSize
.Width() >= aScreen
.Right() )
839 aPos
.X() = rRect
.Left() - rSize
.Width();
841 case WindowAlign::Right
:
842 aPos
= rRect
.TopLeft();
844 devPos
= OutputToAbsoluteScreenPixel( aPos
);
845 if( devPos
.X() - rSize
.Width() > aScreen
.Left() )
846 aPos
.X() -= rSize
.Width();
848 aPos
.X() = rRect
.Right();
857 Rectangle
ToolBox::GetItemRect( sal_uInt16 nItemId
) const
859 if ( mbCalc
|| mbFormat
)
860 const_cast<ToolBox
*>(this)->ImplFormat();
862 sal_uInt16 nPos
= GetItemPos( nItemId
);
863 return GetItemPosRect( nPos
);
866 Rectangle
ToolBox::GetItemPosRect( sal_uInt16 nPos
) const
868 if ( mbCalc
|| mbFormat
)
869 const_cast<ToolBox
*>(this)->ImplFormat();
871 if ( nPos
< mpData
->m_aItems
.size() )
872 return mpData
->m_aItems
[nPos
].maRect
;
877 bool ToolBox::ImplHasExternalMenubutton()
879 // check if the borderwindow (i.e. the decoration) provides the menu button
881 if( ImplIsFloatingMode() )
883 // custom menu is placed in the decoration
884 ImplBorderWindow
*pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
885 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
891 void ToolBox::SetItemBits( sal_uInt16 nItemId
, ToolBoxItemBits nBits
)
893 sal_uInt16 nPos
= GetItemPos( nItemId
);
895 if ( nPos
< mpData
->m_aItems
.size() )
897 ToolBoxItemBits nOldBits
= mpData
->m_aItems
[nPos
].mnBits
;
898 mpData
->m_aItems
[nPos
].mnBits
= nBits
;
899 nBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
900 nOldBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
901 // trigger reformat when the item width has changed (dropdown arrow)
902 bool bFormat
= ToolBoxItemBits(nBits
& ToolBoxItemBits::DROPDOWN
) != ToolBoxItemBits(nOldBits
& ToolBoxItemBits::DROPDOWN
);
903 if ( nBits
!= nOldBits
)
904 ImplInvalidate( true, bFormat
);
908 ToolBoxItemBits
ToolBox::GetItemBits( sal_uInt16 nItemId
) const
910 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
913 return pItem
->mnBits
;
915 return ToolBoxItemBits::NONE
;
918 void ToolBox::SetItemExpand( sal_uInt16 nItemId
, bool bExpand
)
920 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
924 if (pItem
->mbExpand
!= bExpand
)
926 pItem
->mbExpand
= bExpand
;
927 ImplInvalidate(true, true);
931 void ToolBox::SetItemData( sal_uInt16 nItemId
, void* pNewData
)
933 sal_uInt16 nPos
= GetItemPos( nItemId
);
935 if ( nPos
< mpData
->m_aItems
.size() )
937 mpData
->m_aItems
[nPos
].mpUserData
= pNewData
;
938 ImplUpdateItem( nPos
);
942 void* ToolBox::GetItemData( sal_uInt16 nItemId
) const
944 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
947 return pItem
->mpUserData
;
952 void ToolBox::SetItemImage( sal_uInt16 nItemId
, const Image
& rImage
)
954 sal_uInt16 nPos
= GetItemPos( nItemId
);
956 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
958 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
959 Size aOldSize
= pItem
->maImage
.GetSizePixel();
961 pItem
->maImage
= rImage
;
963 // only once all is calculated, do extra work
966 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
967 ImplInvalidate( true );
969 ImplUpdateItem( nPos
);
974 void ToolBox::SetImageList( const ImageList
& rImageList
)
976 maImageList
= rImageList
;
978 sal_uInt16 nCount
= (sal_uInt16
)mpData
->m_aItems
.size();
979 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
982 if ( mpData
->m_aItems
[i
].mnId
)
983 aImage
= maImageList
.GetImage( mpData
->m_aItems
[i
].mnId
);
985 SetItemImage( mpData
->m_aItems
[i
].mnId
, aImage
);
989 static Image
ImplRotImage( const Image
& rImage
, long nAngle10
)
992 BitmapEx
aRotBitmapEx( rImage
.GetBitmapEx() );
994 aRotBitmapEx
.Rotate( nAngle10
, Color( COL_WHITE
) );
996 return Image( aRotBitmapEx
);
999 void ToolBox::SetItemImageAngle( sal_uInt16 nItemId
, long nAngle10
)
1001 sal_uInt16 nPos
= GetItemPos( nItemId
);
1003 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1005 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1006 Size aOldSize
= pItem
->maImage
.GetSizePixel();
1008 long nDeltaAngle
= (nAngle10
- pItem
->mnImageAngle
) % 3600;
1009 while( nDeltaAngle
< 0 )
1010 nDeltaAngle
+= 3600;
1012 pItem
->mnImageAngle
= nAngle10
;
1013 if( nDeltaAngle
&& !!pItem
->maImage
)
1015 pItem
->maImage
= ImplRotImage( pItem
->maImage
, nDeltaAngle
);
1020 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
1021 ImplInvalidate(true);
1023 ImplUpdateItem(nPos
);
1028 static Image
ImplMirrorImage( const Image
& rImage
)
1031 BitmapEx
aMirrBitmapEx( rImage
.GetBitmapEx() );
1033 aMirrBitmapEx
.Mirror( BmpMirrorFlags::Horizontal
);
1035 return Image( aMirrBitmapEx
);
1038 void ToolBox::SetItemImageMirrorMode( sal_uInt16 nItemId
, bool bMirror
)
1040 sal_uInt16 nPos
= GetItemPos( nItemId
);
1042 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1044 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1046 if ((pItem
->mbMirrorMode
&& !bMirror
) ||
1047 (!pItem
->mbMirrorMode
&& bMirror
))
1049 pItem
->mbMirrorMode
= bMirror
;
1050 if (!!pItem
->maImage
)
1052 pItem
->maImage
= ImplMirrorImage(pItem
->maImage
);
1056 ImplUpdateItem(nPos
);
1061 Image
ToolBox::GetItemImage(sal_uInt16 nItemId
) const
1063 ImplToolItem
* pItem
= ImplGetItem(nItemId
);
1064 return pItem
? pItem
->maImage
: Image();
1067 void ToolBox::SetItemText( sal_uInt16 nItemId
, const OUString
& rText
)
1069 sal_uInt16 nPos
= GetItemPos( nItemId
);
1071 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1073 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1074 // only once all is calculated, do extra work
1076 ((meButtonType
!= ButtonType::SYMBOLONLY
) || !pItem
->maImage
) )
1078 long nOldWidth
= GetCtrlTextWidth( pItem
->maText
);
1079 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1080 mpData
->ImplClearLayoutData();
1081 if ( nOldWidth
!= GetCtrlTextWidth( pItem
->maText
) )
1082 ImplInvalidate( true );
1084 ImplUpdateItem( nPos
);
1087 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1089 // Notify button changed event to prepare accessibility bridge
1090 CallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED
, reinterpret_cast< void* >( nPos
) );
1093 CallEventListeners( VCLEVENT_TOOLBOX_ITEMTEXTCHANGED
, reinterpret_cast< void* >( nPos
) );
1097 const OUString
& ToolBox::GetItemText( sal_uInt16 nItemId
) const
1100 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1104 return pItem
->maText
;
1107 void ToolBox::SetItemWindow( sal_uInt16 nItemId
, vcl::Window
* pNewWindow
)
1109 sal_uInt16 nPos
= GetItemPos( nItemId
);
1111 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1113 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1114 pItem
->mpWindow
= pNewWindow
;
1117 ImplInvalidate( true );
1118 CallEventListeners( VCLEVENT_TOOLBOX_ITEMWINDOWCHANGED
, reinterpret_cast< void* >( nPos
) );
1122 vcl::Window
* ToolBox::GetItemWindow( sal_uInt16 nItemId
) const
1124 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1127 return pItem
->mpWindow
;
1132 void ToolBox::StartSelection()
1140 mnCurPos
= TOOLBOX_ITEM_NOTFOUND
;
1146 void ToolBox::EndSelection()
1148 mbCommandDrag
= false;
1150 if ( mbDrag
|| mbSelection
)
1154 mbSelection
= false;
1155 if (mnCurPos
!= TOOLBOX_ITEM_NOTFOUND
)
1156 InvalidateItem(mnCurPos
);
1158 if (IsMouseCaptured())
1163 mnCurPos
= TOOLBOX_ITEM_NOTFOUND
;
1167 mnMouseModifier
= 0;
1170 void ToolBox::SetItemDown( sal_uInt16 nItemId
, bool bDown
)
1172 sal_uInt16 nPos
= GetItemPos( nItemId
);
1174 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1178 if ( nPos
!= mnCurPos
)
1181 InvalidateItem(mnCurPos
);
1187 if ( nPos
== mnCurPos
)
1189 InvalidateItem(mnCurPos
);
1191 mnCurPos
= TOOLBOX_ITEM_NOTFOUND
;
1195 if ( mbDrag
|| mbSelection
)
1198 mbSelection
= false;
1200 if (IsMouseCaptured())
1208 mnMouseModifier
= 0;
1212 void ToolBox::SetItemState( sal_uInt16 nItemId
, TriState eState
)
1214 sal_uInt16 nPos
= GetItemPos( nItemId
);
1216 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1218 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1220 // the state has changed
1221 if ( pItem
->meState
!= eState
)
1223 // if RadioCheck, un-check the previous
1224 if ( (eState
== TRISTATE_TRUE
) && (pItem
->mnBits
& ToolBoxItemBits::AUTOCHECK
) &&
1225 (pItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
) )
1227 ImplToolItem
* pGroupItem
;
1228 sal_uInt16 nGroupPos
;
1229 sal_uInt16 nItemCount
= GetItemCount();
1234 pGroupItem
= &mpData
->m_aItems
[nGroupPos
-1];
1235 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1237 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1238 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1246 while ( nGroupPos
< nItemCount
)
1248 pGroupItem
= &mpData
->m_aItems
[nGroupPos
];
1249 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1251 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1252 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1260 pItem
->meState
= eState
;
1261 ImplUpdateItem( nPos
);
1263 // Notify button changed event to prepare accessibility bridge
1264 CallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED
, reinterpret_cast< void* >( nPos
) );
1266 // Call accessible listener to notify state_changed event
1267 CallEventListeners( VCLEVENT_TOOLBOX_ITEMUPDATED
, reinterpret_cast< void* >(nPos
) );
1272 TriState
ToolBox::GetItemState( sal_uInt16 nItemId
) const
1274 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1277 return pItem
->meState
;
1279 return TRISTATE_FALSE
;
1282 void ToolBox::EnableItem( sal_uInt16 nItemId
, bool bEnable
)
1284 sal_uInt16 nPos
= GetItemPos( nItemId
);
1286 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1288 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1291 if ( pItem
->mbEnabled
!= bEnable
)
1293 pItem
->mbEnabled
= bEnable
;
1295 // if existing, also redraw the window
1296 if ( pItem
->mpWindow
)
1297 pItem
->mpWindow
->Enable( pItem
->mbEnabled
);
1300 ImplUpdateItem( nPos
);
1302 ImplUpdateInputEnable();
1304 // Notify button changed event to prepare accessibility bridge
1305 CallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED
, reinterpret_cast< void* >( nPos
) );
1307 CallEventListeners( bEnable
? VCLEVENT_TOOLBOX_ITEMENABLED
: VCLEVENT_TOOLBOX_ITEMDISABLED
, reinterpret_cast< void* >( nPos
) );
1312 bool ToolBox::IsItemEnabled( sal_uInt16 nItemId
) const
1314 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1317 return pItem
->mbEnabled
;
1322 void ToolBox::ShowItem( sal_uInt16 nItemId
, bool bVisible
)
1324 sal_uInt16 nPos
= GetItemPos( nItemId
);
1325 mpData
->ImplClearLayoutData();
1327 if ( nPos
!= TOOLBOX_ITEM_NOTFOUND
)
1329 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1330 if ( pItem
->mbVisible
!= bVisible
)
1332 pItem
->mbVisible
= bVisible
;
1338 bool ToolBox::IsItemVisible( sal_uInt16 nItemId
) const
1340 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1343 return pItem
->mbVisible
;
1348 bool ToolBox::IsItemReallyVisible( sal_uInt16 nItemId
) const
1350 // is the item on the visible area of the toolbox?
1352 Rectangle
aRect( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
, mnDY
-mnBottomBorder
);
1353 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1355 if ( pItem
&& pItem
->mbVisible
&&
1356 !pItem
->maRect
.IsEmpty() && aRect
.IsOver( pItem
->maRect
) )
1364 void ToolBox::SetItemCommand(sal_uInt16 nItemId
, const OUString
& rCommand
)
1366 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1369 pItem
->maCommandStr
= rCommand
;
1372 const OUString
ToolBox::GetItemCommand( sal_uInt16 nItemId
) const
1374 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1377 return pItem
->maCommandStr
;
1382 void ToolBox::SetQuickHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1384 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1387 pItem
->maQuickHelpText
= rText
;
1390 OUString
ToolBox::GetQuickHelpText( sal_uInt16 nItemId
) const
1392 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1395 return pItem
->maQuickHelpText
;
1400 void ToolBox::SetHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1402 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1405 pItem
->maHelpText
= rText
;
1408 const OUString
& ToolBox::GetHelpText( sal_uInt16 nItemId
) const
1410 return ImplGetHelpText( nItemId
);
1413 void ToolBox::SetHelpId( sal_uInt16 nItemId
, const OString
& rHelpId
)
1415 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1418 pItem
->maHelpId
= rHelpId
;
1421 OString
ToolBox::GetHelpId( sal_uInt16 nItemId
) const
1425 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1429 if ( !pItem
->maHelpId
.isEmpty() )
1430 aRet
= pItem
->maHelpId
;
1432 aRet
= OUStringToOString( pItem
->maCommandStr
, RTL_TEXTENCODING_UTF8
);
1438 void ToolBox::SetOutStyle( sal_uInt16 nNewStyle
)
1440 // always force flat looking toolbars since NWF
1441 nNewStyle
|= TOOLBOX_STYLE_FLAT
;
1443 if ( mnOutStyle
!= nNewStyle
)
1445 mnOutStyle
= nNewStyle
;
1446 ImplDisableFlatButtons();
1448 // so as to redo the ButtonDevice
1449 if ( !(mnOutStyle
& TOOLBOX_STYLE_FLAT
) )
1452 mnMaxItemHeight
= 1;
1455 ImplInvalidate( true, true );
1459 // disable key input if all items are disabled
1460 void ToolBox::ImplUpdateInputEnable()
1462 for( std::vector
< ImplToolItem
>::const_iterator it
= mpData
->m_aItems
.begin();
1463 it
!= mpData
->m_aItems
.end(); ++it
)
1467 // at least one useful entry
1468 mpData
->mbKeyInputDisabled
= false;
1472 mpData
->mbKeyInputDisabled
= true;
1475 void ToolBox::ImplFillLayoutData() const
1477 mpData
->m_pLayoutData
= new ToolBoxLayoutData();
1479 sal_uInt16 nCount
= (sal_uInt16
)mpData
->m_aItems
.size();
1480 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
1482 ImplToolItem
* pItem
= &mpData
->m_aItems
[i
];
1484 // only draw, if the rectangle is within PaintRectangle
1485 if (!pItem
->maRect
.IsEmpty())
1486 const_cast<ToolBox
*>(this)->InvalidateItem(i
);
1490 OUString
ToolBox::GetDisplayText() const
1492 if( ! mpData
->m_pLayoutData
)
1493 ImplFillLayoutData();
1494 return mpData
->m_pLayoutData
? OUString(mpData
->m_pLayoutData
->m_aDisplayText
) : OUString();
1497 Rectangle
ToolBox::GetCharacterBounds( sal_uInt16 nItemID
, long nIndex
) const
1499 long nItemIndex
= -1;
1500 if( ! mpData
->m_pLayoutData
)
1501 ImplFillLayoutData();
1502 if( mpData
->m_pLayoutData
)
1504 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineItemIds
.size(); i
++ )
1506 if( mpData
->m_pLayoutData
->m_aLineItemIds
[i
] == nItemID
)
1508 nItemIndex
= mpData
->m_pLayoutData
->m_aLineIndices
[i
];
1513 return (mpData
->m_pLayoutData
&& nItemIndex
!= -1) ? mpData
->m_pLayoutData
->GetCharacterBounds( nItemIndex
+nIndex
) : Rectangle();
1516 long ToolBox::GetIndexForPoint( const Point
& rPoint
, sal_uInt16
& rItemID
) const
1520 if( ! mpData
->m_pLayoutData
)
1521 ImplFillLayoutData();
1522 if( mpData
->m_pLayoutData
)
1524 nIndex
= mpData
->m_pLayoutData
->GetIndexForPoint( rPoint
);
1525 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineIndices
.size(); i
++ )
1527 if( mpData
->m_pLayoutData
->m_aLineIndices
[i
] <= nIndex
&&
1528 (i
== mpData
->m_pLayoutData
->m_aLineIndices
.size()-1 || mpData
->m_pLayoutData
->m_aLineIndices
[i
+1] > nIndex
) )
1530 rItemID
= mpData
->m_pLayoutData
->m_aLineItemIds
[i
];
1538 void ToolBox::SetDropdownClickHdl( const Link
<ToolBox
*, void>& rLink
)
1540 if (mpData
!= nullptr) {
1541 mpData
->maDropdownClickHdl
= rLink
;
1545 void ToolBox::SetMenuType( ToolBoxMenuType aType
)
1547 if( aType
!= mpData
->maMenuType
)
1549 mpData
->maMenuType
= aType
;
1550 if( IsFloatingMode() )
1552 // the menu button may have to be moved into the decoration which changes the layout
1553 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1555 pWrapper
->ShowTitleButton( TitleButton::Menu
, bool( aType
& ToolBoxMenuType::Customize
) );
1559 ImplSetMinMaxFloatSize( this );
1563 // trigger redraw of menu button
1564 if( !mpData
->maMenubuttonItem
.maRect
.IsEmpty() )
1565 Invalidate(mpData
->maMenubuttonItem
.maRect
);
1570 ToolBoxMenuType
ToolBox::GetMenuType() const
1572 return mpData
->maMenuType
;
1575 bool ToolBox::IsMenuEnabled() const
1577 return mpData
->maMenuType
!= ToolBoxMenuType::NONE
;
1580 PopupMenu
* ToolBox::GetMenu() const
1582 return mpData
== nullptr ? nullptr : mpData
->mpMenu
;
1585 void ToolBox::SetMenuButtonHdl( const Link
<ToolBox
*, void>& rLink
)
1587 mpData
->maMenuButtonHdl
= rLink
;
1590 bool ToolBox::ImplHasClippedItems()
1592 // are any items currently clipped ?
1594 std::vector
< ImplToolItem
>::const_iterator it
= mpData
->m_aItems
.begin();
1595 while ( it
!= mpData
->m_aItems
.end() )
1597 if( it
->IsClipped() )
1606 MenuItemBits
ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits
)
1608 MenuItemBits nMenuItemBits
= MenuItemBits::NONE
;
1609 if ((nToolItemBits
& ToolBoxItemBits::CHECKABLE
) ||
1610 (nToolItemBits
& ToolBoxItemBits::DROPDOWN
))
1612 nMenuItemBits
|= MenuItemBits::CHECKABLE
;
1614 return nMenuItemBits
;
1618 void ToolBox::UpdateCustomMenu()
1620 // fill clipped items into menu
1621 if( !IsMenuEnabled() )
1624 PopupMenu
*pMenu
= GetMenu();
1627 // remove old entries
1628 while( i
< pMenu
->GetItemCount() )
1630 if( pMenu
->GetItemId( i
) >= TOOLBOX_MENUITEM_START
)
1632 pMenu
->RemoveItem( i
);
1639 // add menu items: first the overflow items, then hidden items, both in the
1640 // order they would usually appear in the toolbar. Separators that would be
1641 // in the toolbar are ignored as they would introduce too much clutter,
1642 // instead we have a single separator to help distinguish between overflow
1643 // and hidden items.
1644 if ( !mpData
->m_aItems
.empty() )
1646 // nStartPos will hold the number of clipped items appended from first loop
1647 for ( std::vector
< ImplToolItem
>::iterator
it(mpData
->m_aItems
.begin());
1648 it
!= mpData
->m_aItems
.end(); ++it
)
1650 if( it
->IsClipped() )
1652 sal_uInt16 id
= it
->mnId
+ TOOLBOX_MENUITEM_START
;
1653 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(it
->mnBits
);
1654 pMenu
->InsertItem( id
, it
->maText
, it
->maImage
, nMenuItemBits
);
1655 pMenu
->SetItemCommand( id
, it
->maCommandStr
);
1656 pMenu
->EnableItem( id
, it
->mbEnabled
);
1657 pMenu
->CheckItem ( id
, it
->meState
== TRISTATE_TRUE
);
1661 // add a separator below the inserted clipped-items
1662 pMenu
->InsertSeparator();
1664 // now append the items that are explicitly disabled
1665 for ( std::vector
< ImplToolItem
>::iterator
it(mpData
->m_aItems
.begin());
1666 it
!= mpData
->m_aItems
.end(); ++it
)
1668 if( it
->IsItemHidden() )
1670 sal_uInt16 id
= it
->mnId
+ TOOLBOX_MENUITEM_START
;
1671 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(it
->mnBits
);
1672 pMenu
->InsertItem( id
, it
->maText
, it
->maImage
, nMenuItemBits
);
1673 pMenu
->SetItemCommand( id
, it
->maCommandStr
);
1674 pMenu
->EnableItem( id
, it
->mbEnabled
);
1675 pMenu
->CheckItem( id
, it
->meState
== TRISTATE_TRUE
);
1682 IMPL_LINK( ToolBox
, ImplCustomMenuListener
, VclMenuEvent
&, rEvent
, void )
1684 if( rEvent
.GetMenu() == GetMenu() && rEvent
.GetId() == VCLEVENT_MENU_SELECT
)
1686 sal_uInt16 id
= GetMenu()->GetItemId( rEvent
.GetItemPos() );
1687 if( id
>= TOOLBOX_MENUITEM_START
)
1688 TriggerItem( id
- TOOLBOX_MENUITEM_START
);
1692 IMPL_LINK_NOARG(ToolBox
, ImplCallExecuteCustomMenu
, void*, void)
1694 mpData
->mnEventId
= nullptr;
1695 if( IsMenuEnabled() )
1697 if( GetMenuType() & ToolBoxMenuType::Customize
)
1698 // call button handler to allow for menu customization
1699 mpData
->maMenuButtonHdl
.Call( this );
1701 // We specifically only register this event listener when executing our
1702 // overflow menu (and remove it directly afterwards), as the same menu
1703 // is reused for both the overflow menu (as managed here in ToolBox),
1704 // but also by ToolBarManager for its context menu. If we leave event
1705 // listeners alive beyond when the menu is showing in the desired mode
1706 // then duplicate events can happen as the context menu "duplicates"
1707 // items from the overflow menu, which both listeners would then act on.
1708 GetMenu()->AddEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1710 // make sure all disabled entries will be shown
1711 GetMenu()->SetMenuFlags(
1712 GetMenu()->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries
);
1714 // toolbox might be destroyed during execute
1715 bool bBorderDel
= false;
1717 VclPtr
<vcl::Window
> pWin
= this;
1718 Rectangle aMenuRect
= mpData
->maMenubuttonItem
.maRect
;
1719 VclPtr
<ImplBorderWindow
> pBorderWin
;
1720 if( IsFloatingMode() )
1722 // custom menu is placed in the decoration
1723 pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
1724 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
1727 aMenuRect
= pBorderWin
->GetMenuRect();
1732 sal_uInt16 uId
= GetMenu()->Execute( pWin
, Rectangle( ImplGetPopupPosition( aMenuRect
, Size() ), Size() ),
1733 PopupMenuFlags::ExecuteDown
| PopupMenuFlags::NoMouseUpClose
);
1735 if ( pWin
->IsDisposed() )
1739 GetMenu()->RemoveEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1742 if( pBorderWin
->IsDisposed() )
1746 pWin
->Invalidate( aMenuRect
);
1749 GrabFocusToDocument();
1753 void ToolBox::ExecuteCustomMenu()
1755 if( IsMenuEnabled() )
1757 // handle custom menu asynchronously
1758 // to avoid problems if the toolbox is closed during menu execute
1760 mpData
->mnEventId
= Application::PostUserEvent( LINK( this, ToolBox
, ImplCallExecuteCustomMenu
), nullptr, true );
1764 // checks override first, useful during calculation of sizes
1765 bool ToolBox::ImplIsFloatingMode() const
1767 SAL_WARN_IF( mpData
->mbAssumeDocked
&& mpData
->mbAssumeFloating
, "vcl",
1768 "cannot assume docked and floating" );
1770 if( mpData
->mbAssumeDocked
)
1772 else if( mpData
->mbAssumeFloating
)
1775 return IsFloatingMode();
1778 // checks override first, useful during calculation of sizes
1779 bool ToolBox::ImplIsInPopupMode() const
1781 if( mpData
->mbAssumePopupMode
)
1785 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1786 return ( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() );
1790 void ToolBox::Lock( bool bLock
)
1792 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1795 if( mpData
->mbIsLocked
!= bLock
)
1797 mpData
->mbIsLocked
= bLock
;
1798 if( !ImplIsFloatingMode() )
1802 SetSizePixel( CalcWindowSizePixel(1) );
1808 bool ToolBox::AlwaysLocked()
1810 // read config item to determine toolbox behaviour, used for subtoolbars
1812 static int nAlwaysLocked
= -1;
1814 if( nAlwaysLocked
== -1 )
1816 nAlwaysLocked
= 0; // ask configuration only once
1818 utl::OConfigurationNode aNode
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1819 comphelper::getProcessComponentContext(),
1820 "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ); // note: case sensitive !
1821 if ( aNode
.isValid() )
1823 // feature enabled ?
1824 bool bStatesEnabled
= bool();
1825 css::uno::Any aValue
= aNode
.getNodeValue( OUString("StatesEnabled") );
1826 if( aValue
>>= bStatesEnabled
)
1828 if( bStatesEnabled
)
1830 // now read the locking state
1831 utl::OConfigurationNode aNode2
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1832 comphelper::getProcessComponentContext(),
1833 "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ); // note: case sensitive !
1835 bool bLocked
= bool();
1836 css::uno::Any aValue2
= aNode2
.getNodeValue( OUString("Locked") );
1837 if( aValue2
>>= bLocked
)
1838 nAlwaysLocked
= bLocked
? 1 : 0;
1844 return nAlwaysLocked
== 1;
1847 bool ToolBox::WillUsePopupMode() const
1849 return mpData
->mbWillUsePopupMode
;
1852 void ToolBox::WillUsePopupMode( bool b
)
1854 mpData
->mbWillUsePopupMode
= b
;
1857 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */