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 <vcl/uitest/logger.hxx>
22 #include <sal/log.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <boost/property_tree/ptree.hpp>
27 #include <vcl/svapp.hxx>
28 #include <vcl/idle.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>
42 #include <tools/json_writer.hxx>
44 #include <vcl/uitest/uiobject.hxx>
48 #define TB_SEP_SIZE 8 // Separator size
51 ImplToolBoxPrivateData::ImplToolBoxPrivateData()
53 meButtonSize
= ToolBoxButtonSize::DontCare
;
54 mpMenu
= VclPtr
<PopupMenu
>::Create();
56 maMenuType
= ToolBoxMenuType::NONE
;
57 maMenubuttonItem
.maItemSize
= Size( TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
, TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
);
58 maMenubuttonItem
.meState
= TRISTATE_FALSE
;
59 mnMenuButtonWidth
= TB_MENUBUTTON_SIZE
;
62 mbNativeButtons
= false;
63 mbIsPaintLocked
= false;
64 mbAssumeDocked
= false;
65 mbAssumePopupMode
= false;
66 mbAssumeFloating
= false;
67 mbKeyInputDisabled
= false;
68 mbMenubuttonSelected
= false;
69 mbMenubuttonWasLastSelected
= false;
70 mbWillUsePopupMode
= false;
71 mbDropDownByKeyboard
= false;
74 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
76 m_pLayoutData
.reset();
77 mpMenu
.disposeAndClear();
80 void ImplToolItem::init(sal_uInt16 nItemId
, ToolBoxItemBits nItemBits
,
85 mbNonInteractiveWindow
= false;
87 meType
= ToolBoxItemType::BUTTON
;
89 meState
= TRISTATE_FALSE
;
92 mbEmptyBtn
= bEmptyBtn
;
95 mnSepSize
= TB_SEP_SIZE
;
96 mnDropDownArrowWidth
= TB_DROPDOWNARROWWIDTH
;
97 mnImageAngle
= Degree10(0);
99 mbVisibleText
= false;
103 ImplToolItem::ImplToolItem()
105 init(0, ToolBoxItemBits::NONE
, true);
108 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
109 ToolBoxItemBits nItemBits
) :
112 init(nItemId
, nItemBits
, false);
115 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const OUString
& rText
,
116 ToolBoxItemBits nItemBits
) :
119 init(nItemId
, nItemBits
, false);
122 ImplToolItem::ImplToolItem( sal_uInt16 nItemId
, const Image
& rImage
,
123 const OUString
& rText
, ToolBoxItemBits nItemBits
) :
127 init(nItemId
, nItemBits
, false);
130 Size
ImplToolItem::GetSize( bool bHorz
, bool bCheckMaxWidth
, tools::Long maxWidth
, const Size
& rDefaultSize
)
132 Size
aSize( rDefaultSize
); // the size of 'standard' toolbox items
133 // non-standard items are eg windows or buttons with text
135 if ( (meType
== ToolBoxItemType::BUTTON
) || (meType
== ToolBoxItemType::SPACE
) )
139 if ( mpWindow
&& bHorz
)
141 // get size of item window and check if it fits
142 // no windows in vertical toolbars (the default is mbShowWindow=false)
143 Size aWinSize
= mpWindow
->GetSizePixel();
145 if (mpWindow
->GetStyle() & WB_NOLABEL
)
146 // Window wants no label? Then don't check width, it'll be just
148 bCheckMaxWidth
= false;
150 if ( !bCheckMaxWidth
|| (aWinSize
.Width() <= maxWidth
) )
152 aSize
.setWidth( aWinSize
.Width() );
153 aSize
.setHeight( aWinSize
.Height() );
161 aSize
.setHeight( 0 );
166 else if ( meType
== ToolBoxItemType::SEPARATOR
)
170 aSize
.setWidth( mnSepSize
);
171 aSize
.setHeight( rDefaultSize
.Height() );
175 aSize
.setWidth( rDefaultSize
.Width() );
176 aSize
.setHeight( mnSepSize
);
179 else if ( meType
== ToolBoxItemType::BREAK
)
182 aSize
.setHeight( 0 );
188 void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType
, bool& rbImage
, bool& rbText
) const
190 if ( meType
!= ToolBoxItemType::BUTTON
)
192 // no button -> draw nothing
193 rbImage
= rbText
= false;
200 // check for image and/or text
201 bHasImage
= !!maImage
;
202 bHasText
= !maText
.isEmpty();
204 // prefer images if symbolonly buttons are drawn
205 // prefer texts if textonly buttons are drawn
207 if ( eButtonType
== ButtonType::SYMBOLONLY
) // drawing icons only
209 if( bHasImage
|| !bHasText
)
220 else if ( eButtonType
== ButtonType::TEXT
) // drawing text only
222 if( bHasText
|| !bHasImage
)
233 else // drawing icons and text both
240 tools::Rectangle
ImplToolItem::GetDropDownRect( bool bHorz
) const
242 tools::Rectangle aRect
;
243 if( (mnBits
& ToolBoxItemBits::DROPDOWN
) && !maRect
.IsEmpty() )
246 if( mbVisibleText
&& !bHorz
)
247 // item will be rotated -> place dropdown to the bottom
248 aRect
.SetTop( aRect
.Bottom() - mnDropDownArrowWidth
);
250 // place dropdown to the right
251 aRect
.SetLeft( aRect
.Right() - mnDropDownArrowWidth
);
256 bool ImplToolItem::IsClipped() const
258 return ( meType
== ToolBoxItemType::BUTTON
&& mbVisible
&& maRect
.IsEmpty() );
261 bool ImplToolItem::IsItemHidden() const
263 return ( meType
== ToolBoxItemType::BUTTON
&& !mbVisible
);
266 void ToolBox::ImplInvalidate( bool bNewCalc
, bool bFullPaint
)
268 ImplUpdateInputEnable();
277 // do we need to redraw?
278 if ( IsReallyVisible() && IsUpdateMode() )
280 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
,
281 mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
291 // do we need to redraw?
292 if ( IsReallyVisible() && IsUpdateMode() )
297 // request new layout by layoutmanager
298 CallEventListeners( VclEventId::ToolboxFormatChanged
);
301 void ToolBox::ImplUpdateItem( ImplToolItems::size_type nIndex
)
303 // do we need to redraw?
304 if ( !(IsReallyVisible() && IsUpdateMode()) )
307 if ( nIndex
== ITEM_NOTFOUND
)
309 // #i52217# no immediate draw as this might lead to paint problems
310 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
316 // #i52217# no immediate draw as this might lead to paint problems
317 Invalidate( mpData
->m_aItems
[nIndex
].maRect
);
320 maPaintRect
.Union( mpData
->m_aItems
[nIndex
].maRect
);
324 void ToolBox::Click()
326 CallEventListeners( VclEventId::ToolboxClick
);
327 maClickHdl
.Call( this );
328 UITestLogger::getInstance().logAction( this, VclEventId::ToolboxClick
);
331 void ToolBox::DoubleClick()
333 CallEventListeners( VclEventId::ToolboxDoubleClick
);
334 maDoubleClickHdl
.Call( this );
337 void ToolBox::Activate()
340 CallEventListeners( VclEventId::ToolboxActivate
);
341 maActivateHdl
.Call( this );
344 void ToolBox::Deactivate()
347 CallEventListeners( VclEventId::ToolboxDeactivate
);
348 maDeactivateHdl
.Call( this );
351 void ToolBox::Highlight()
353 CallEventListeners( VclEventId::ToolboxHighlight
);
356 FactoryFunction
ToolBox::GetUITestFactory() const
358 return ToolBoxUIObject::create
;
361 void ToolBox::Select()
363 VclPtr
<vcl::Window
> xWindow
= this;
365 CallEventListeners( VclEventId::ToolboxSelect
);
366 maSelectHdl
.Call( this );
368 if ( xWindow
->IsDisposed() )
371 // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
372 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
373 if( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() )
374 pWrapper
->GetFloatingWindow()->EndPopupMode();
377 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
379 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
380 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
381 "ToolBox::InsertItem(): ItemId already exists" );
383 // create item and add to list
384 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
385 ImplToolItem( nItemId
, rImage
, nBits
) );
386 mpData
->ImplClearLayoutData();
388 ImplInvalidate( true );
391 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
392 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >(nNewPos
) );
395 void ToolBox::InsertItem( sal_uInt16 nItemId
, const Image
& rImage
, const OUString
& rText
, ToolBoxItemBits nBits
,
396 ImplToolItems::size_type nPos
)
398 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
399 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
400 "ToolBox::InsertItem(): ItemId already exists" );
402 // create item and add to list
403 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
404 ImplToolItem( nItemId
, rImage
, MnemonicGenerator::EraseAllMnemonicChars(rText
), nBits
) );
405 mpData
->ImplClearLayoutData();
407 ImplInvalidate( true );
410 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
411 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
414 void ToolBox::InsertItem( sal_uInt16 nItemId
, const OUString
& rText
, ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
416 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
417 SAL_WARN_IF( GetItemPos( nItemId
) != 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 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
429 CallEventListeners( VclEventId::ToolboxItemAdded
, 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
, ImplToolItems::size_type nPos
)
435 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
436 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(rCommand
, aModuleName
);
437 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
438 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(rCommand
, aProperties
, rFrame
));
439 Image
aImage(CommandInfoProvider::GetImageForCommand(rCommand
, rFrame
, GetImageSize()));
441 sal_uInt16 nItemId
= GetItemCount() + 1;
442 //TODO: ImplToolItems::size_type -> sal_uInt16!
443 InsertItem(nItemId
, aImage
, aLabel
, nBits
, nPos
);
444 SetItemCommand(nItemId
, rCommand
);
445 SetQuickHelpText(nItemId
, aTooltip
);
447 // set the minimal size
448 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
450 pItem
->maMinimalItemSize
= rRequestedSize
;
453 void ToolBox::InsertWindow( sal_uInt16 nItemId
, vcl::Window
* pWindow
,
454 ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
456 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertWindow(): ItemId == 0" );
457 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
458 "ToolBox::InsertWindow(): ItemId already exists" );
460 // create item and add to list
462 aItem
.mnId
= nItemId
;
463 aItem
.meType
= ToolBoxItemType::BUTTON
;
464 aItem
.mnBits
= nBits
;
465 aItem
.mpWindow
= pWindow
;
466 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
467 mpData
->ImplClearLayoutData();
472 ImplInvalidate( true );
475 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
476 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
479 void ToolBox::InsertSpace()
481 // create item and add to list
483 aItem
.meType
= ToolBoxItemType::SPACE
;
484 aItem
.mbEnabled
= false;
485 mpData
->m_aItems
.push_back( aItem
);
486 mpData
->ImplClearLayoutData();
491 ImplToolItems::size_type nNewPos
= mpData
->m_aItems
.size() - 1;
492 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
495 void ToolBox::InsertSeparator( ImplToolItems::size_type nPos
, sal_uInt16 nPixSize
)
497 // create item and add to list
499 aItem
.meType
= ToolBoxItemType::SEPARATOR
;
500 aItem
.mbEnabled
= false;
502 aItem
.mnSepSize
= nPixSize
;
503 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
504 mpData
->ImplClearLayoutData();
509 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
510 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
513 void ToolBox::InsertBreak( ImplToolItems::size_type nPos
)
515 // create item and add to list
517 aItem
.meType
= ToolBoxItemType::BREAK
;
518 aItem
.mbEnabled
= false;
519 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
520 mpData
->ImplClearLayoutData();
525 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
526 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
529 void ToolBox::RemoveItem( ImplToolItems::size_type nPos
)
531 if( nPos
>= mpData
->m_aItems
.size() )
535 bMustCalc
= mpData
->m_aItems
[nPos
].meType
== ToolBoxItemType::BUTTON
;
537 if ( mpData
->m_aItems
[nPos
].mpWindow
)
538 mpData
->m_aItems
[nPos
].mpWindow
->Hide();
540 // add the removed item to PaintRect
541 maPaintRect
.Union( mpData
->m_aItems
[nPos
].maRect
);
543 // ensure not to delete in the Select-Handler
544 if ( mpData
->m_aItems
[nPos
].mnId
== mnCurItemId
)
546 if ( mpData
->m_aItems
[nPos
].mnId
== mnHighItemId
)
549 ImplInvalidate( bMustCalc
);
551 mpData
->m_aItems
.erase( mpData
->m_aItems
.begin()+nPos
);
552 mpData
->ImplClearLayoutData();
555 CallEventListeners( VclEventId::ToolboxItemRemoved
, reinterpret_cast< void* >( nPos
) );
558 void ToolBox::CopyItem( const ToolBox
& rToolBox
, sal_uInt16 nItemId
)
560 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
561 "ToolBox::CopyItem(): ItemId already exists" );
563 ImplToolItems::size_type nPos
= rToolBox
.GetItemPos( nItemId
);
566 if ( nPos
== ITEM_NOTFOUND
)
569 // push ToolBox item onto the list
570 ImplToolItem aNewItem
= rToolBox
.mpData
->m_aItems
[nPos
];
572 aNewItem
.mpWindow
= nullptr;
573 aNewItem
.mbShowWindow
= false;
575 mpData
->m_aItems
.push_back( aNewItem
);
576 mpData
->ImplClearLayoutData();
581 ImplToolItems::size_type nNewPos2
= mpData
->m_aItems
.size() - 1;
582 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos2
) );
585 void ToolBox::Clear()
587 mpData
->m_aItems
.clear();
588 mpData
->ImplClearLayoutData();
590 // ensure not to delete in the Select-Handler
594 ImplInvalidate( true, true );
597 CallEventListeners( VclEventId::ToolboxAllItemsChanged
);
600 void ToolBox::SetButtonType( ButtonType eNewType
)
602 if ( meButtonType
!= eNewType
)
604 meButtonType
= eNewType
;
606 // better redraw everything, as otherwise there might be problems
607 // with regions that were copied with CopyBits
608 ImplInvalidate( true );
612 void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize
)
614 if( mpData
->meButtonSize
!= eSize
)
616 mpData
->meButtonSize
= eSize
;
622 ToolBoxButtonSize
ToolBox::GetToolboxButtonSize() const
624 return mpData
->meButtonSize
;
627 ImageType
ToolBox::GetImageSize() const
629 ImageType eImageType
= ImageType::Size16
;
630 if (mpData
->meButtonSize
== ToolBoxButtonSize::Large
)
631 eImageType
= ImageType::Size26
;
632 else if (mpData
->meButtonSize
== ToolBoxButtonSize::Size32
)
633 eImageType
= ImageType::Size32
;
638 /*static*/ Size
ToolBox::GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize
)
640 OutputDevice
*pDefault
= Application::GetDefaultDevice();
641 float fScaleFactor
= pDefault
? pDefault
->GetDPIScaleFactor() : 1.0;
643 Size
aUnscaledSize(16, 16);
645 if (eToolBoxButtonSize
== ToolBoxButtonSize::Large
)
647 OUString iconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
648 aUnscaledSize
= vcl::IconThemeInfo::SizeByThemeName(iconTheme
);
650 else if (eToolBoxButtonSize
== ToolBoxButtonSize::Size32
)
652 aUnscaledSize
= Size(32, 32);
654 return Size(aUnscaledSize
.Width() * fScaleFactor
,
655 aUnscaledSize
.Height() * fScaleFactor
);
658 Size
ToolBox::GetDefaultImageSize() const
660 return GetDefaultImageSize(GetToolboxButtonSize());
663 void ToolBox::SetAlign( WindowAlign eNewAlign
)
665 if ( meAlign
== eNewAlign
)
670 if ( ImplIsFloatingMode() )
673 // set horizontal/vertical alignment
674 if ( (eNewAlign
== WindowAlign::Left
) || (eNewAlign
== WindowAlign::Right
) )
679 // Update the background according to Persona if necessary
680 ImplInitSettings( false, false, true );
682 // redraw everything, as the border has changed
685 if ( IsReallyVisible() && IsUpdateMode() )
689 void ToolBox::SetLineCount( ImplToolItems::size_type nNewLines
)
694 if ( mnLines
!= nNewLines
)
698 // better redraw everything, as otherwise there might be problems
699 // with regions that were copied with CopyBits
704 ToolBox::ImplToolItems::size_type
ToolBox::GetItemCount() const
706 return mpData
? mpData
->m_aItems
.size() : 0;
709 ToolBoxItemType
ToolBox::GetItemType( ImplToolItems::size_type nPos
) const
711 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].meType
: ToolBoxItemType::DONTKNOW
;
714 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( sal_uInt16 nItemId
) const
718 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
719 for( ImplToolItems::size_type nPos
= 0; nPos
< nCount
; nPos
++ )
720 if( mpData
->m_aItems
[nPos
].mnId
== nItemId
)
723 return ITEM_NOTFOUND
;
726 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( const Point
& rPos
) const
728 // search the item position on the given point
729 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
730 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.IsInside( rPos
); });
732 if( it
!= mpData
->m_aItems
.end() )
733 return std::distance(mpData
->m_aItems
.begin(), it
);
735 return ITEM_NOTFOUND
;
738 sal_uInt16
ToolBox::GetItemId( ImplToolItems::size_type nPos
) const
740 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].mnId
: 0;
743 sal_uInt16
ToolBox::GetItemId( const Point
& rPos
) const
745 // find item that was clicked
746 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
747 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.IsInside( rPos
); });
749 if( (it
!= mpData
->m_aItems
.end()) && (it
->meType
== ToolBoxItemType::BUTTON
) )
755 Size
ToolBox::GetItemContentSize( sal_uInt16 nItemId
)
757 if ( mbCalc
|| mbFormat
)
760 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
761 if ( nPos
< mpData
->m_aItems
.size() )
762 return mpData
->m_aItems
[nPos
].maContentSize
;
767 sal_uInt16
ToolBox::GetItemId(const OUString
&rCommand
) const
772 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
773 [&rCommand
](const ImplToolItem
& rItem
) { return rItem
.maCommandStr
== rCommand
; });
774 if (it
!= mpData
->m_aItems
.end())
780 Point
ToolBox::ImplGetPopupPosition( const tools::Rectangle
& rRect
) const
783 if( !rRect
.IsEmpty() )
785 tools::Rectangle aScreen
= GetDesktopRectPixel();
787 // the popup should be positioned so that it will not cover
788 // the item rect and that it fits the desktop
789 // the preferred direction is always towards the center of
790 // the application window
792 Point devPos
; // the position in device coordinates for screen comparison
795 case WindowAlign::Top
:
796 aPos
= rRect
.BottomLeft();
798 devPos
= OutputToAbsoluteScreenPixel( aPos
);
799 if( devPos
.Y() >= aScreen
.Bottom() )
800 aPos
.setY( rRect
.Top() );
802 case WindowAlign::Bottom
:
803 aPos
= rRect
.TopLeft();
805 devPos
= OutputToAbsoluteScreenPixel( aPos
);
806 if( devPos
.Y() <= aScreen
.Top() )
807 aPos
.setY( rRect
.Bottom() );
809 case WindowAlign::Left
:
810 aPos
= rRect
.TopRight();
812 devPos
= OutputToAbsoluteScreenPixel( aPos
);
813 if( devPos
.X() >= aScreen
.Right() )
814 aPos
.setX( rRect
.Left() );
816 case WindowAlign::Right
:
817 aPos
= rRect
.TopLeft();
819 devPos
= OutputToAbsoluteScreenPixel( aPos
);
820 if( devPos
.X() <= aScreen
.Left() )
821 aPos
.setX( rRect
.Right() );
830 tools::Rectangle
ToolBox::GetItemRect( sal_uInt16 nItemId
)
832 if ( mbCalc
|| mbFormat
)
835 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
836 return GetItemPosRect( nPos
);
839 tools::Rectangle
ToolBox::GetItemPosRect( ImplToolItems::size_type nPos
)
841 if ( mbCalc
|| mbFormat
)
844 if ( nPos
< mpData
->m_aItems
.size() )
845 return mpData
->m_aItems
[nPos
].maRect
;
847 return tools::Rectangle();
850 tools::Rectangle
const & ToolBox::GetOverflowRect() const
852 return mpData
->maMenubuttonItem
.maRect
;
855 bool ToolBox::ImplHasExternalMenubutton()
857 // check if the borderwindow (i.e. the decoration) provides the menu button
859 if( ImplIsFloatingMode() )
861 // custom menu is placed in the decoration
862 ImplBorderWindow
*pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
863 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
869 void ToolBox::SetItemBits( sal_uInt16 nItemId
, ToolBoxItemBits nBits
)
871 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
873 if ( nPos
< GetItemCount() )
875 ToolBoxItemBits nOldBits
= mpData
->m_aItems
[nPos
].mnBits
;
876 mpData
->m_aItems
[nPos
].mnBits
= nBits
;
877 nBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
878 nOldBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
879 // trigger reformat when the item width has changed (dropdown arrow)
880 bool bFormat
= ToolBoxItemBits(nBits
& ToolBoxItemBits::DROPDOWN
) != ToolBoxItemBits(nOldBits
& ToolBoxItemBits::DROPDOWN
);
881 if ( nBits
!= nOldBits
)
882 ImplInvalidate( true, bFormat
);
886 void ToolBox::SetItemWindowNonInteractive(sal_uInt16 nItemId
, bool bNonInteractive
)
888 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
890 if ( nPos
< GetItemCount() )
892 mpData
->m_aItems
[nPos
].mbNonInteractiveWindow
= bNonInteractive
;
896 ToolBoxItemBits
ToolBox::GetItemBits( sal_uInt16 nItemId
) const
898 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
901 return pItem
->mnBits
;
903 return ToolBoxItemBits::NONE
;
906 void ToolBox::SetItemExpand( sal_uInt16 nItemId
, bool bExpand
)
908 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
912 if (pItem
->mbExpand
!= bExpand
)
914 pItem
->mbExpand
= bExpand
;
915 ImplInvalidate(true, true);
919 void ToolBox::SetItemData( sal_uInt16 nItemId
, void* pNewData
)
921 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
923 if ( nPos
< mpData
->m_aItems
.size() )
925 mpData
->m_aItems
[nPos
].mpUserData
= pNewData
;
926 ImplUpdateItem( nPos
);
930 void* ToolBox::GetItemData( sal_uInt16 nItemId
) const
932 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
935 return pItem
->mpUserData
;
940 void ToolBox::SetItemImage( sal_uInt16 nItemId
, const Image
& rImage
)
942 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
944 if ( nPos
== ITEM_NOTFOUND
)
947 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
948 Size aOldSize
= pItem
->maImage
.GetSizePixel();
950 pItem
->maImage
= rImage
;
952 // only once all is calculated, do extra work
955 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
956 ImplInvalidate( true );
958 ImplUpdateItem( nPos
);
962 static Image
ImplRotImage( const Image
& rImage
, Degree10 nAngle10
)
964 BitmapEx
aRotBitmapEx( rImage
.GetBitmapEx() );
966 aRotBitmapEx
.Rotate( nAngle10
, COL_WHITE
);
968 return Image( aRotBitmapEx
);
971 void ToolBox::SetItemImageAngle( sal_uInt16 nItemId
, Degree10 nAngle10
)
973 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
975 if ( nPos
== ITEM_NOTFOUND
)
978 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
979 Size aOldSize
= pItem
->maImage
.GetSizePixel();
981 Degree10 nDeltaAngle
= (nAngle10
- pItem
->mnImageAngle
) % Degree10(3600);
982 while( nDeltaAngle
< Degree10(0) )
983 nDeltaAngle
+= Degree10(3600);
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
);
1000 static Image
ImplMirrorImage( const Image
& rImage
)
1002 BitmapEx
aMirrBitmapEx( rImage
.GetBitmapEx() );
1004 aMirrBitmapEx
.Mirror( BmpMirrorFlags::Horizontal
);
1006 return Image( aMirrBitmapEx
);
1009 void ToolBox::SetItemImageMirrorMode( sal_uInt16 nItemId
, bool bMirror
)
1011 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1013 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
);
1031 Image
ToolBox::GetItemImage(sal_uInt16 nItemId
) const
1033 ImplToolItem
* pItem
= ImplGetItem(nItemId
);
1034 return pItem
? pItem
->maImage
: Image();
1037 void ToolBox::SetItemText( sal_uInt16 nItemId
, const OUString
& rText
)
1039 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1041 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 tools::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
) );
1067 const OUString
& ToolBox::GetItemText( sal_uInt16 nItemId
) const
1070 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1074 return pItem
->maText
;
1077 void ToolBox::SetItemWindow( sal_uInt16 nItemId
, vcl::Window
* pNewWindow
)
1079 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1081 if ( nPos
!= ITEM_NOTFOUND
)
1083 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1084 pItem
->mpWindow
= pNewWindow
;
1087 ImplInvalidate( true );
1088 CallEventListeners( VclEventId::ToolboxItemWindowChanged
, reinterpret_cast< void* >( nPos
) );
1092 vcl::Window
* ToolBox::GetItemWindow( sal_uInt16 nItemId
) const
1094 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1097 return pItem
->mpWindow
;
1102 void ToolBox::EndSelection()
1108 if (mnCurPos
!= ITEM_NOTFOUND
)
1109 InvalidateItem(mnCurPos
);
1111 if (IsMouseCaptured())
1116 mnCurPos
= ITEM_NOTFOUND
;
1119 mnMouseModifier
= 0;
1122 void ToolBox::SetItemDown( sal_uInt16 nItemId
, bool bDown
)
1124 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1126 if ( nPos
== ITEM_NOTFOUND
)
1131 if ( nPos
!= mnCurPos
)
1134 InvalidateItem(mnCurPos
);
1140 if ( nPos
== mnCurPos
)
1142 InvalidateItem(mnCurPos
);
1144 mnCurPos
= ITEM_NOTFOUND
;
1152 if (IsMouseCaptured())
1159 mnMouseModifier
= 0;
1162 void ToolBox::SetItemState( sal_uInt16 nItemId
, TriState eState
)
1164 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1166 if ( nPos
== ITEM_NOTFOUND
)
1169 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1171 // the state has changed
1172 if ( pItem
->meState
== eState
)
1175 // if RadioCheck, un-check the previous
1176 if ( (eState
== TRISTATE_TRUE
) && (pItem
->mnBits
& ToolBoxItemBits::AUTOCHECK
) &&
1177 (pItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
) )
1179 ImplToolItem
* pGroupItem
;
1180 ImplToolItems::size_type nGroupPos
;
1181 ImplToolItems::size_type nItemCount
= GetItemCount();
1186 pGroupItem
= &mpData
->m_aItems
[nGroupPos
-1];
1187 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1189 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1190 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1198 while ( nGroupPos
< nItemCount
)
1200 pGroupItem
= &mpData
->m_aItems
[nGroupPos
];
1201 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1203 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1204 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1212 pItem
->meState
= eState
;
1213 ImplUpdateItem( nPos
);
1215 // Notify button changed event to prepare accessibility bridge
1216 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1218 // Call accessible listener to notify state_changed event
1219 CallEventListeners( VclEventId::ToolboxItemUpdated
, reinterpret_cast< void* >(nPos
) );
1222 TriState
ToolBox::GetItemState( sal_uInt16 nItemId
) const
1224 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1227 return pItem
->meState
;
1229 return TRISTATE_FALSE
;
1232 void ToolBox::EnableItem( sal_uInt16 nItemId
, bool bEnable
)
1234 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1236 if ( nPos
== ITEM_NOTFOUND
)
1239 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1240 if ( pItem
->mbEnabled
== bEnable
)
1243 pItem
->mbEnabled
= bEnable
;
1245 // if existing, also redraw the window
1246 if ( pItem
->mpWindow
)
1247 pItem
->mpWindow
->Enable( pItem
->mbEnabled
);
1250 ImplUpdateItem( nPos
);
1252 ImplUpdateInputEnable();
1254 // Notify button changed event to prepare accessibility bridge
1255 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1257 CallEventListeners( bEnable
? VclEventId::ToolboxItemEnabled
: VclEventId::ToolboxItemDisabled
, reinterpret_cast< void* >( nPos
) );
1260 bool ToolBox::IsItemEnabled( sal_uInt16 nItemId
) const
1262 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1265 return pItem
->mbEnabled
;
1270 void ToolBox::ShowItem( sal_uInt16 nItemId
, bool bVisible
)
1272 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1273 mpData
->ImplClearLayoutData();
1275 if ( nPos
!= ITEM_NOTFOUND
)
1277 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1278 if ( pItem
->mbVisible
!= bVisible
)
1280 pItem
->mbVisible
= bVisible
;
1286 bool ToolBox::IsItemClipped( sal_uInt16 nItemId
) const
1288 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1291 return pItem
->IsClipped();
1296 bool ToolBox::IsItemVisible( sal_uInt16 nItemId
) const
1298 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1301 return pItem
->mbVisible
;
1306 bool ToolBox::IsItemReallyVisible( sal_uInt16 nItemId
) const
1308 // is the item on the visible area of the toolbox?
1310 tools::Rectangle
aRect( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
, mnDY
-mnBottomBorder
);
1311 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1313 if ( pItem
&& pItem
->mbVisible
&&
1314 !pItem
->maRect
.IsEmpty() && aRect
.IsOver( pItem
->maRect
) )
1322 void ToolBox::SetItemCommand(sal_uInt16 nItemId
, const OUString
& rCommand
)
1324 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1327 pItem
->maCommandStr
= rCommand
;
1330 OUString
ToolBox::GetItemCommand( sal_uInt16 nItemId
) const
1332 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1335 return pItem
->maCommandStr
;
1340 void ToolBox::SetQuickHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1342 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1345 pItem
->maQuickHelpText
= rText
;
1348 OUString
ToolBox::GetQuickHelpText( sal_uInt16 nItemId
) const
1350 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1353 return pItem
->maQuickHelpText
;
1358 void ToolBox::SetHelpText( sal_uInt16 nItemId
, const OUString
& rText
)
1360 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1363 pItem
->maHelpText
= rText
;
1366 const OUString
& ToolBox::GetHelpText( sal_uInt16 nItemId
) const
1368 return ImplGetHelpText( nItemId
);
1371 void ToolBox::SetHelpId( sal_uInt16 nItemId
, const OString
& rHelpId
)
1373 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1376 pItem
->maHelpId
= rHelpId
;
1379 // disable key input if all items are disabled
1380 void ToolBox::ImplUpdateInputEnable()
1382 mpData
->mbKeyInputDisabled
= std::none_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1383 [](const ImplToolItem
& rItem
) {
1384 // at least one useful entry
1385 return rItem
.mbEnabled
;
1389 void ToolBox::ImplFillLayoutData()
1391 mpData
->m_pLayoutData
.reset(new ToolBoxLayoutData
);
1393 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
1394 for( ImplToolItems::size_type i
= 0; i
< nCount
; i
++ )
1396 ImplToolItem
* pItem
= &mpData
->m_aItems
[i
];
1398 // only draw, if the rectangle is within PaintRectangle
1399 if (!pItem
->maRect
.IsEmpty())
1404 OUString
ToolBox::GetDisplayText() const
1406 if( ! mpData
->m_pLayoutData
)
1407 const_cast<ToolBox
*>(this)->ImplFillLayoutData();
1408 return mpData
->m_pLayoutData
? mpData
->m_pLayoutData
->m_aDisplayText
: OUString();
1411 tools::Rectangle
ToolBox::GetCharacterBounds( sal_uInt16 nItemID
, tools::Long nIndex
)
1413 tools::Long nItemIndex
= -1;
1414 if( ! mpData
->m_pLayoutData
)
1415 ImplFillLayoutData();
1416 if( mpData
->m_pLayoutData
)
1418 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineItemIds
.size(); i
++ )
1420 if( mpData
->m_pLayoutData
->m_aLineItemIds
[i
] == nItemID
)
1422 nItemIndex
= mpData
->m_pLayoutData
->m_aLineIndices
[i
];
1427 return (mpData
->m_pLayoutData
&& nItemIndex
!= -1) ? mpData
->m_pLayoutData
->GetCharacterBounds( nItemIndex
+nIndex
) : tools::Rectangle();
1430 tools::Long
ToolBox::GetIndexForPoint( const Point
& rPoint
, sal_uInt16
& rItemID
)
1432 tools::Long nIndex
= -1;
1434 if( ! mpData
->m_pLayoutData
)
1435 ImplFillLayoutData();
1436 if( mpData
->m_pLayoutData
)
1438 nIndex
= mpData
->m_pLayoutData
->GetIndexForPoint( rPoint
);
1439 for( sal_uLong i
= 0; i
< mpData
->m_pLayoutData
->m_aLineIndices
.size(); i
++ )
1441 if( mpData
->m_pLayoutData
->m_aLineIndices
[i
] <= nIndex
&&
1442 (i
== mpData
->m_pLayoutData
->m_aLineIndices
.size()-1 || mpData
->m_pLayoutData
->m_aLineIndices
[i
+1] > nIndex
) )
1444 rItemID
= mpData
->m_pLayoutData
->m_aLineItemIds
[i
];
1452 void ToolBox::SetDropdownClickHdl( const Link
<ToolBox
*, void>& rLink
)
1454 if (mpData
!= nullptr) {
1455 mpData
->maDropdownClickHdl
= rLink
;
1459 void ToolBox::SetMenuType( ToolBoxMenuType aType
)
1461 if( aType
== mpData
->maMenuType
)
1464 mpData
->maMenuType
= aType
;
1465 if( IsFloatingMode() )
1467 // the menu button may have to be moved into the decoration which changes the layout
1468 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1470 pWrapper
->ShowTitleButton( TitleButton::Menu
, bool( aType
& ToolBoxMenuType::Customize
) );
1474 ImplSetMinMaxFloatSize();
1478 // trigger redraw of menu button
1479 if( !mpData
->maMenubuttonItem
.maRect
.IsEmpty() )
1480 Invalidate(mpData
->maMenubuttonItem
.maRect
);
1484 ToolBoxMenuType
ToolBox::GetMenuType() const
1486 return mpData
->maMenuType
;
1489 bool ToolBox::IsMenuEnabled() const
1491 return mpData
->maMenuType
!= ToolBoxMenuType::NONE
;
1494 PopupMenu
* ToolBox::GetMenu() const
1496 return mpData
== nullptr ? nullptr : mpData
->mpMenu
;
1499 void ToolBox::SetMenuExecuteHdl( const Link
<ToolBox
*, void>& rLink
)
1501 mpData
->maMenuButtonHdl
= rLink
;
1504 bool ToolBox::ImplHasClippedItems()
1506 // are any items currently clipped ?
1508 return std::any_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1509 [](const ImplToolItem
& rItem
) { return rItem
.IsClipped(); });
1514 MenuItemBits
ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits
)
1516 MenuItemBits nMenuItemBits
= MenuItemBits::NONE
;
1517 if ((nToolItemBits
& ToolBoxItemBits::CHECKABLE
) ||
1518 (nToolItemBits
& ToolBoxItemBits::DROPDOWN
))
1520 nMenuItemBits
|= MenuItemBits::CHECKABLE
;
1522 return nMenuItemBits
;
1526 void ToolBox::UpdateCustomMenu()
1528 // fill clipped items into menu
1529 PopupMenu
*pMenu
= GetMenu();
1532 // add menu items: first the overflow items, then hidden items, both in the
1533 // order they would usually appear in the toolbar. Separators that would be
1534 // in the toolbar are ignored as they would introduce too much clutter,
1535 // instead we have a single separator to help distinguish between overflow
1536 // and hidden items.
1537 if ( mpData
->m_aItems
.empty() )
1540 // nStartPos will hold the number of clipped items appended from first loop
1541 for ( const auto& rItem
: mpData
->m_aItems
)
1543 if( rItem
.IsClipped() )
1545 sal_uInt16 id
= rItem
.mnId
+ TOOLBOX_MENUITEM_START
;
1546 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1547 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1548 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1549 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1550 pMenu
->CheckItem ( id
, rItem
.meState
== TRISTATE_TRUE
);
1554 // add a separator below the inserted clipped-items
1555 pMenu
->InsertSeparator();
1557 // now append the items that are explicitly disabled
1558 for ( const auto& rItem
: mpData
->m_aItems
)
1560 if( rItem
.IsItemHidden() )
1562 sal_uInt16 id
= rItem
.mnId
+ TOOLBOX_MENUITEM_START
;
1563 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1564 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1565 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1566 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1567 pMenu
->CheckItem( id
, rItem
.meState
== TRISTATE_TRUE
);
1572 IMPL_LINK( ToolBox
, ImplCustomMenuListener
, VclMenuEvent
&, rEvent
, void )
1574 if( rEvent
.GetMenu() == GetMenu() && rEvent
.GetId() == VclEventId::MenuSelect
)
1576 sal_uInt16 id
= GetMenu()->GetItemId( rEvent
.GetItemPos() );
1577 if( id
>= TOOLBOX_MENUITEM_START
)
1578 TriggerItem( id
- TOOLBOX_MENUITEM_START
);
1582 void ToolBox::ExecuteCustomMenu( const tools::Rectangle
& rRect
)
1584 if ( !IsMenuEnabled() || ImplIsInPopupMode() )
1589 if( GetMenuType() & ToolBoxMenuType::Customize
)
1590 // call button handler to allow for menu customization
1591 mpData
->maMenuButtonHdl
.Call( this );
1593 GetMenu()->AddEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1595 // make sure all disabled entries will be shown
1596 GetMenu()->SetMenuFlags(
1597 GetMenu()->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries
);
1599 // toolbox might be destroyed during execute
1600 bool bBorderDel
= false;
1602 VclPtr
<vcl::Window
> pWin
= this;
1603 tools::Rectangle aMenuRect
= rRect
;
1604 VclPtr
<ImplBorderWindow
> pBorderWin
;
1605 if( aMenuRect
.IsEmpty() && IsFloatingMode() )
1607 // custom menu is placed in the decoration
1608 pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
1609 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
1612 aMenuRect
= pBorderWin
->GetMenuRect();
1617 sal_uInt16 uId
= GetMenu()->Execute( pWin
, tools::Rectangle( ImplGetPopupPosition( aMenuRect
), Size() ),
1618 PopupMenuFlags::ExecuteDown
| PopupMenuFlags::NoMouseUpClose
);
1620 if ( pWin
->IsDisposed() )
1624 GetMenu()->RemoveEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1627 if( pBorderWin
->IsDisposed() )
1631 pWin
->Invalidate( aMenuRect
);
1634 GrabFocusToDocument();
1637 // checks override first, useful during calculation of sizes
1638 bool ToolBox::ImplIsFloatingMode() const
1640 SAL_WARN_IF( mpData
->mbAssumeDocked
&& mpData
->mbAssumeFloating
, "vcl",
1641 "cannot assume docked and floating" );
1643 if( mpData
->mbAssumeDocked
)
1645 else if( mpData
->mbAssumeFloating
)
1648 return IsFloatingMode();
1651 // checks override first, useful during calculation of sizes
1652 bool ToolBox::ImplIsInPopupMode() const
1654 if( mpData
->mbAssumePopupMode
)
1658 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1659 return ( pWrapper
&& pWrapper
->GetFloatingWindow() && pWrapper
->GetFloatingWindow()->IsInPopupMode() );
1663 void ToolBox::Lock( bool bLock
)
1665 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1668 if( mpData
->mbIsLocked
!= bLock
)
1670 mpData
->mbIsLocked
= bLock
;
1671 if( !ImplIsFloatingMode() )
1675 SetSizePixel( CalcWindowSizePixel(1) );
1681 bool ToolBox::AlwaysLocked()
1683 // read config item to determine toolbox behaviour, used for subtoolbars
1685 static int nAlwaysLocked
= -1;
1687 if( nAlwaysLocked
== -1 )
1689 nAlwaysLocked
= 0; // ask configuration only once
1691 utl::OConfigurationNode aNode
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1692 comphelper::getProcessComponentContext(),
1693 "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ); // note: case sensitive !
1694 if ( aNode
.isValid() )
1696 // feature enabled ?
1697 bool bStatesEnabled
= bool();
1698 css::uno::Any aValue
= aNode
.getNodeValue( "StatesEnabled" );
1699 if( aValue
>>= bStatesEnabled
)
1701 if( bStatesEnabled
)
1703 // now read the locking state
1704 utl::OConfigurationNode aNode2
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1705 comphelper::getProcessComponentContext(),
1706 "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ); // note: case sensitive !
1708 bool bLocked
= bool();
1709 css::uno::Any aValue2
= aNode2
.getNodeValue( "Locked" );
1710 if( aValue2
>>= bLocked
)
1711 nAlwaysLocked
= bLocked
? 1 : 0;
1717 return nAlwaysLocked
== 1;
1720 bool ToolBox::WillUsePopupMode() const
1722 return mpData
->mbWillUsePopupMode
;
1725 void ToolBox::WillUsePopupMode( bool b
)
1727 mpData
->mbWillUsePopupMode
= b
;
1730 void ToolBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
1732 DockingWindow::DumpAsPropertyTree(rJsonWriter
);
1734 auto childrenNode
= rJsonWriter
.startNode("children");
1735 for (ToolBox::ImplToolItems::size_type i
= 0; i
< GetItemCount(); ++i
)
1737 ToolBoxItemType type
= GetItemType(i
);
1738 if (type
== ToolBoxItemType::BUTTON
)
1740 auto childNode
= rJsonWriter
.startNode("");
1741 int nId
= GetItemId(i
);
1742 if (!IsItemVisible(nId
))
1744 rJsonWriter
.put("type", "toolitem");
1745 rJsonWriter
.put("text", GetItemText(nId
));
1746 rJsonWriter
.put("command", GetItemCommand(nId
));
1751 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */