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 <vcl/uitest/logger.hxx>
23 #include <sal/log.hxx>
25 #include <comphelper/base64.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <boost/property_tree/ptree.hpp>
29 #include <vcl/cvtgrf.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/idle.hxx>
32 #include <vcl/bitmap.hxx>
33 #include <vcl/toolkit/floatwin.hxx>
34 #include <vcl/toolbox.hxx>
35 #include <vcl/mnemonic.hxx>
36 #include <vcl/menu.hxx>
37 #include <vcl/settings.hxx>
38 #include <vcl/IconThemeInfo.hxx>
39 #include <vcl/commandinfoprovider.hxx>
45 #include <unotools/confignode.hxx>
46 #include <tools/json_writer.hxx>
48 #include <vcl/uitest/uiobject.hxx>
50 #include "impldockingwrapper.hxx"
54 #define TB_SEP_SIZE 8 // Separator size
57 ImplToolBoxPrivateData::ImplToolBoxPrivateData()
59 meButtonSize
= ToolBoxButtonSize::DontCare
;
60 mpMenu
= VclPtr
<PopupMenu
>::Create();
62 maMenuType
= ToolBoxMenuType::NONE
;
63 maMenubuttonItem
.maItemSize
= Size( TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
, TB_MENUBUTTON_SIZE
+TB_MENUBUTTON_OFFSET
);
64 maMenubuttonItem
.meState
= TRISTATE_FALSE
;
65 mnMenuButtonWidth
= TB_MENUBUTTON_SIZE
;
68 mbNativeButtons
= false;
69 mbIsPaintLocked
= false;
70 mbAssumeDocked
= false;
71 mbAssumePopupMode
= false;
72 mbAssumeFloating
= false;
73 mbKeyInputDisabled
= false;
74 mbMenubuttonSelected
= false;
75 mbMenubuttonWasLastSelected
= false;
76 mbWillUsePopupMode
= false;
77 mbDropDownByKeyboard
= false;
80 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
82 m_pLayoutData
.reset();
83 mpMenu
.disposeAndClear();
86 void ImplToolItem::init(ToolBoxItemId nItemId
, ToolBoxItemBits nItemBits
,
91 mbNonInteractiveWindow
= false;
93 meType
= ToolBoxItemType::BUTTON
;
95 meState
= TRISTATE_FALSE
;
98 mbEmptyBtn
= bEmptyBtn
;
101 mnSepSize
= TB_SEP_SIZE
;
102 mnDropDownArrowWidth
= TB_DROPDOWNARROWWIDTH
;
103 mnImageAngle
= 0_deg10
;
104 mbMirrorMode
= false;
105 mbVisibleText
= false;
109 ImplToolItem::ImplToolItem()
111 init(ToolBoxItemId(0), ToolBoxItemBits::NONE
, true);
114 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId
, Image aImage
,
115 ToolBoxItemBits nItemBits
) :
116 maImage(std::move( aImage
))
118 init(nItemId
, nItemBits
, false);
121 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId
, OUString aText
,
122 OUString aCommand
, ToolBoxItemBits nItemBits
) :
123 maText(std::move( aText
)),
124 maCommandStr(std::move( aCommand
))
126 init(nItemId
, nItemBits
, false);
129 ImplToolItem::ImplToolItem( ToolBoxItemId nItemId
, Image aImage
,
130 OUString aText
, ToolBoxItemBits nItemBits
) :
131 maImage(std::move( aImage
)),
132 maText(std::move( aText
))
134 init(nItemId
, nItemBits
, false);
137 Size
ImplToolItem::GetSize( bool bHorz
, bool bCheckMaxWidth
, tools::Long maxWidth
, const Size
& rDefaultSize
)
139 Size
aSize( rDefaultSize
); // the size of 'standard' toolbox items
140 // non-standard items are eg windows or buttons with text
142 if ( (meType
== ToolBoxItemType::BUTTON
) || (meType
== ToolBoxItemType::SPACE
) )
146 if ( mpWindow
&& bHorz
)
148 // get size of item window and check if it fits
149 // no windows in vertical toolbars (the default is mbShowWindow=false)
150 Size aWinSize
= mpWindow
->GetSizePixel();
152 if (mpWindow
->GetStyle() & WB_NOLABEL
)
153 // Window wants no label? Then don't check width, it'll be just
155 bCheckMaxWidth
= false;
157 if ( !bCheckMaxWidth
|| (aWinSize
.Width() <= maxWidth
) )
159 aSize
.setWidth( aWinSize
.Width() );
160 aSize
.setHeight( aWinSize
.Height() );
168 aSize
.setHeight( 0 );
173 else if ( meType
== ToolBoxItemType::SEPARATOR
)
177 aSize
.setWidth( mnSepSize
);
178 aSize
.setHeight( rDefaultSize
.Height() );
182 aSize
.setWidth( rDefaultSize
.Width() );
183 aSize
.setHeight( mnSepSize
);
186 else if ( meType
== ToolBoxItemType::BREAK
)
189 aSize
.setHeight( 0 );
195 void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType
, bool& rbImage
, bool& rbText
) const
197 if ( meType
!= ToolBoxItemType::BUTTON
)
199 // no button -> draw nothing
200 rbImage
= rbText
= false;
207 // check for image and/or text
208 bHasImage
= !!maImage
;
209 bHasText
= !maText
.isEmpty();
211 // prefer images if symbolonly buttons are drawn
212 // prefer texts if textonly buttons are drawn
214 if ( eButtonType
== ButtonType::SYMBOLONLY
) // drawing icons only
216 if( bHasImage
|| !bHasText
)
227 else if ( eButtonType
== ButtonType::TEXT
) // drawing text only
229 if( bHasText
|| !bHasImage
)
240 else // drawing icons and text both
247 tools::Rectangle
ImplToolItem::GetDropDownRect( bool bHorz
) const
249 tools::Rectangle aRect
;
250 if( (mnBits
& ToolBoxItemBits::DROPDOWN
) && !maRect
.IsEmpty() )
253 if( mbVisibleText
&& !bHorz
)
254 // item will be rotated -> place dropdown to the bottom
255 aRect
.SetTop( aRect
.Bottom() - mnDropDownArrowWidth
);
257 // place dropdown to the right
258 aRect
.SetLeft( aRect
.Right() - mnDropDownArrowWidth
);
263 bool ImplToolItem::IsClipped() const
265 return ( meType
== ToolBoxItemType::BUTTON
&& mbVisible
&& maRect
.IsEmpty() );
268 bool ImplToolItem::IsItemHidden() const
270 return ( meType
== ToolBoxItemType::BUTTON
&& !mbVisible
);
273 void ToolBox::ImplInvalidate( bool bNewCalc
, bool bFullPaint
)
275 ImplUpdateInputEnable();
284 // do we need to redraw?
285 if ( IsReallyVisible() && IsUpdateMode() )
287 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
,
288 mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
298 // do we need to redraw?
299 if ( IsReallyVisible() && IsUpdateMode() )
304 // request new layout by layoutmanager
305 CallEventListeners( VclEventId::ToolboxFormatChanged
);
308 void ToolBox::ImplUpdateItem( ImplToolItems::size_type nIndex
)
310 // do we need to redraw?
311 if ( !(IsReallyVisible() && IsUpdateMode()) )
314 if ( nIndex
== ITEM_NOTFOUND
)
316 // #i52217# no immediate draw as this might lead to paint problems
317 Invalidate( tools::Rectangle( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
-1, mnDY
-mnBottomBorder
-1 ) );
323 // #i52217# no immediate draw as this might lead to paint problems
324 Invalidate( mpData
->m_aItems
[nIndex
].maRect
);
327 maPaintRect
.Union( mpData
->m_aItems
[nIndex
].maRect
);
331 void ToolBox::Click()
333 CallEventListeners( VclEventId::ToolboxClick
);
334 maClickHdl
.Call( this );
335 UITestLogger::getInstance().logAction( this, VclEventId::ToolboxClick
);
338 void ToolBox::DoubleClick()
340 CallEventListeners( VclEventId::ToolboxDoubleClick
);
341 maDoubleClickHdl
.Call( this );
344 void ToolBox::Activate()
347 CallEventListeners( VclEventId::ToolboxActivate
);
348 maActivateHdl
.Call( this );
351 void ToolBox::Deactivate()
354 CallEventListeners( VclEventId::ToolboxDeactivate
);
355 maDeactivateHdl
.Call( this );
358 void ToolBox::Highlight()
360 CallEventListeners( VclEventId::ToolboxHighlight
);
363 FactoryFunction
ToolBox::GetUITestFactory() const
365 return ToolBoxUIObject::create
;
368 void ToolBox::Select()
370 VclPtr
<vcl::Window
> xWindow
= this;
372 CallEventListeners( VclEventId::ToolboxSelect
);
373 maSelectHdl
.Call( this );
375 if ( xWindow
->isDisposed() )
378 // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper
379 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
380 if( pWrapper
&& pWrapper
->GetFloatingWindow() && static_cast<FloatingWindow
*>(pWrapper
->GetFloatingWindow())->IsInPopupMode() )
381 static_cast<FloatingWindow
*>(pWrapper
->GetFloatingWindow())->EndPopupMode();
384 void ToolBox::InsertItem( ToolBoxItemId nItemId
, const Image
& rImage
, ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
386 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
387 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
388 "ToolBox::InsertItem(): ItemId already exists" );
390 // create item and add to list
391 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
392 ImplToolItem( nItemId
, rImage
, nBits
) );
393 mpData
->ImplClearLayoutData();
395 ImplInvalidate( true );
398 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
399 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >(nNewPos
) );
402 void ToolBox::InsertItem( ToolBoxItemId nItemId
, const Image
& rImage
, const OUString
& rText
, ToolBoxItemBits nBits
,
403 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
, rImage
, 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( ToolBoxItemId nItemId
, const OUString
& rText
, const OUString
& rCommand
, ToolBoxItemBits nBits
,
422 ImplToolItems::size_type nPos
)
424 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertItem(): ItemId == 0" );
425 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
426 "ToolBox::InsertItem(): ItemId already exists" );
428 // create item and add to list
429 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(),
430 ImplToolItem( nItemId
, MnemonicGenerator::EraseAllMnemonicChars(rText
), rCommand
, nBits
) );
431 mpData
->ImplClearLayoutData();
433 ImplInvalidate( true );
436 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
437 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
440 void ToolBox::InsertItem(const OUString
& rCommand
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
, ToolBoxItemBits nBits
,
441 const Size
& rRequestedSize
, ImplToolItems::size_type nPos
)
443 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
444 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(rCommand
, aModuleName
);
445 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
446 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(rCommand
, aProperties
, rFrame
));
447 Image
aImage(CommandInfoProvider::GetImageForCommand(rCommand
, rFrame
, GetImageSize()));
449 ToolBoxItemId
nItemId(GetItemCount() + 1);
450 //TODO: ImplToolItems::size_type -> sal_uInt16!
451 InsertItem(nItemId
, aLabel
, rCommand
, nBits
, nPos
);
452 SetItemImage(nItemId
, aImage
);
453 SetQuickHelpText(nItemId
, aTooltip
);
455 // set the minimal size
456 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
458 pItem
->maMinimalItemSize
= rRequestedSize
;
461 void ToolBox::InsertWindow( ToolBoxItemId nItemId
, vcl::Window
* pWindow
,
462 ToolBoxItemBits nBits
, ImplToolItems::size_type nPos
)
464 SAL_WARN_IF( !nItemId
, "vcl", "ToolBox::InsertWindow(): ItemId == 0" );
465 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
466 "ToolBox::InsertWindow(): ItemId already exists" );
468 // create item and add to list
470 aItem
.mnId
= nItemId
;
471 aItem
.meType
= ToolBoxItemType::BUTTON
;
472 aItem
.mnBits
= nBits
;
473 aItem
.mpWindow
= pWindow
;
474 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
475 mpData
->ImplClearLayoutData();
480 ImplInvalidate( true );
483 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
484 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
487 void ToolBox::InsertSpace()
489 // create item and add to list
491 aItem
.meType
= ToolBoxItemType::SPACE
;
492 aItem
.mbEnabled
= false;
493 mpData
->m_aItems
.push_back( aItem
);
494 mpData
->ImplClearLayoutData();
499 ImplToolItems::size_type nNewPos
= mpData
->m_aItems
.size() - 1;
500 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
503 void ToolBox::InsertSeparator( ImplToolItems::size_type nPos
, sal_uInt16 nPixSize
)
505 // create item and add to list
507 aItem
.meType
= ToolBoxItemType::SEPARATOR
;
508 aItem
.mbEnabled
= false;
510 aItem
.mnSepSize
= nPixSize
;
511 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
512 mpData
->ImplClearLayoutData();
517 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
518 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
521 void ToolBox::InsertBreak( ImplToolItems::size_type nPos
)
523 // create item and add to list
525 aItem
.meType
= ToolBoxItemType::BREAK
;
526 aItem
.mbEnabled
= false;
527 mpData
->m_aItems
.insert( (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
.begin()+nPos
: mpData
->m_aItems
.end(), aItem
);
528 mpData
->ImplClearLayoutData();
533 ImplToolItems::size_type nNewPos
= ( nPos
== APPEND
) ? ( mpData
->m_aItems
.size() - 1 ) : nPos
;
534 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos
) );
537 void ToolBox::RemoveItem( ImplToolItems::size_type nPos
)
539 if( nPos
>= mpData
->m_aItems
.size() )
543 bMustCalc
= 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
)
553 mnCurItemId
= ToolBoxItemId(0);
554 if ( mpData
->m_aItems
[nPos
].mnId
== mnHighItemId
)
555 mnHighItemId
= ToolBoxItemId(0);
557 ImplInvalidate( bMustCalc
);
559 mpData
->m_aItems
.erase( mpData
->m_aItems
.begin()+nPos
);
560 mpData
->ImplClearLayoutData();
563 CallEventListeners( VclEventId::ToolboxItemRemoved
, reinterpret_cast< void* >( nPos
) );
566 void ToolBox::CopyItem( const ToolBox
& rToolBox
, ToolBoxItemId nItemId
)
568 SAL_WARN_IF( GetItemPos( nItemId
) != ITEM_NOTFOUND
, "vcl",
569 "ToolBox::CopyItem(): ItemId already exists" );
571 ImplToolItems::size_type nPos
= rToolBox
.GetItemPos( nItemId
);
574 if ( nPos
== 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 ImplToolItems::size_type nNewPos2
= mpData
->m_aItems
.size() - 1;
590 CallEventListeners( VclEventId::ToolboxItemAdded
, reinterpret_cast< void* >( nNewPos2
) );
593 void ToolBox::Clear()
595 mpData
->m_aItems
.clear();
596 mpData
->ImplClearLayoutData();
598 // ensure not to delete in the Select-Handler
599 mnCurItemId
= ToolBoxItemId(0);
600 mnHighItemId
= ToolBoxItemId(0);
602 ImplInvalidate( true, true );
605 CallEventListeners( VclEventId::ToolboxAllItemsChanged
);
608 void ToolBox::SetButtonType( ButtonType eNewType
)
610 if ( meButtonType
!= eNewType
)
612 meButtonType
= eNewType
;
614 // better redraw everything, as otherwise there might be problems
615 // with regions that were copied with CopyBits
616 ImplInvalidate( true );
620 void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize
)
622 if( mpData
->meButtonSize
!= eSize
)
624 mpData
->meButtonSize
= eSize
;
630 ToolBoxButtonSize
ToolBox::GetToolboxButtonSize() const
632 return mpData
->meButtonSize
;
635 ImageType
ToolBox::GetImageSize() const
637 ImageType eImageType
= ImageType::Size16
;
638 if (mpData
->meButtonSize
== ToolBoxButtonSize::Large
)
639 eImageType
= ImageType::Size26
;
640 else if (mpData
->meButtonSize
== ToolBoxButtonSize::Size32
)
641 eImageType
= ImageType::Size32
;
646 /*static*/ Size
ToolBox::GetDefaultImageSize(ToolBoxButtonSize eToolBoxButtonSize
)
648 OutputDevice
*pDefault
= Application::GetDefaultDevice();
649 float fScaleFactor
= pDefault
? pDefault
->GetDPIScaleFactor() : 1.0;
651 Size
aUnscaledSize(16, 16);
653 if (eToolBoxButtonSize
== ToolBoxButtonSize::Large
)
655 OUString iconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
656 aUnscaledSize
= vcl::IconThemeInfo::SizeByThemeName(iconTheme
);
658 else if (eToolBoxButtonSize
== ToolBoxButtonSize::Size32
)
660 aUnscaledSize
= Size(32, 32);
662 return Size(aUnscaledSize
.Width() * fScaleFactor
,
663 aUnscaledSize
.Height() * fScaleFactor
);
666 Size
ToolBox::GetDefaultImageSize() const
668 return GetDefaultImageSize(GetToolboxButtonSize());
671 void ToolBox::SetAlign( WindowAlign eNewAlign
)
673 if ( meAlign
== eNewAlign
)
678 if ( ImplIsFloatingMode() )
681 // set horizontal/vertical alignment
682 if ( (eNewAlign
== WindowAlign::Left
) || (eNewAlign
== WindowAlign::Right
) )
687 // Update the background according to Persona if necessary
688 ImplInitSettings( false, false, true );
690 // redraw everything, as the border has changed
693 if ( IsReallyVisible() && IsUpdateMode() )
697 void ToolBox::SetLineCount( ImplToolItems::size_type nNewLines
)
702 if ( mnLines
!= nNewLines
)
706 // better redraw everything, as otherwise there might be problems
707 // with regions that were copied with CopyBits
712 ToolBox::ImplToolItems::size_type
ToolBox::GetItemCount() const
714 return mpData
? mpData
->m_aItems
.size() : 0;
717 ToolBoxItemType
ToolBox::GetItemType( ImplToolItems::size_type nPos
) const
719 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].meType
: ToolBoxItemType::DONTKNOW
;
722 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( ToolBoxItemId nItemId
) const
726 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
727 for( ImplToolItems::size_type nPos
= 0; nPos
< nCount
; nPos
++ )
728 if( mpData
->m_aItems
[nPos
].mnId
== nItemId
)
731 return ITEM_NOTFOUND
;
734 ToolBox::ImplToolItems::size_type
ToolBox::GetItemPos( const Point
& rPos
) const
736 // search the item position on the given point
737 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
738 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.Contains( rPos
); });
740 if( it
!= mpData
->m_aItems
.end() )
741 return std::distance(mpData
->m_aItems
.begin(), it
);
743 return ITEM_NOTFOUND
;
746 ToolBoxItemId
ToolBox::GetItemId( ImplToolItems::size_type nPos
) const
748 return (nPos
< mpData
->m_aItems
.size()) ? mpData
->m_aItems
[nPos
].mnId
: ToolBoxItemId(0);
751 ToolBoxItemId
ToolBox::GetItemId( const Point
& rPos
) const
753 // find item that was clicked
754 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
755 [&rPos
](const ImplToolItem
& rItem
) { return rItem
.maRect
.Contains( rPos
); });
757 if( (it
!= mpData
->m_aItems
.end()) && (it
->meType
== ToolBoxItemType::BUTTON
) )
760 return ToolBoxItemId(0);
763 Size
ToolBox::GetItemContentSize( ToolBoxItemId nItemId
)
765 if ( mbCalc
|| mbFormat
)
768 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
769 if ( nPos
< mpData
->m_aItems
.size() )
770 return mpData
->m_aItems
[nPos
].maContentSize
;
775 ToolBoxItemId
ToolBox::GetItemId(const OUString
&rCommand
) const
778 return ToolBoxItemId(0);
780 auto it
= std::find_if(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
781 [&rCommand
](const ImplToolItem
& rItem
) { return rItem
.maCommandStr
== rCommand
; });
782 if (it
!= mpData
->m_aItems
.end())
785 return ToolBoxItemId(0);
788 Point
ToolBox::ImplGetPopupPosition( const tools::Rectangle
& rRect
) const
791 if( !rRect
.IsEmpty() )
793 tools::Rectangle aScreen
= GetDesktopRectPixel();
795 // the popup should be positioned so that it will not cover
796 // the item rect and that it fits the desktop
797 // the preferred direction is always towards the center of
798 // the application window
800 Point devPos
; // the position in device coordinates for screen comparison
803 case WindowAlign::Top
:
804 aPos
= rRect
.BottomLeft();
806 devPos
= OutputToAbsoluteScreenPixel( aPos
);
807 if( devPos
.Y() >= aScreen
.Bottom() )
808 aPos
.setY( rRect
.Top() );
810 case WindowAlign::Bottom
:
811 aPos
= rRect
.TopLeft();
813 devPos
= OutputToAbsoluteScreenPixel( aPos
);
814 if( devPos
.Y() <= aScreen
.Top() )
815 aPos
.setY( rRect
.Bottom() );
817 case WindowAlign::Left
:
818 aPos
= rRect
.TopRight();
820 devPos
= OutputToAbsoluteScreenPixel( aPos
);
821 if( devPos
.X() >= aScreen
.Right() )
822 aPos
.setX( rRect
.Left() );
824 case WindowAlign::Right
:
825 aPos
= rRect
.TopLeft();
827 devPos
= OutputToAbsoluteScreenPixel( aPos
);
828 if( devPos
.X() <= aScreen
.Left() )
829 aPos
.setX( rRect
.Right() );
838 tools::Rectangle
ToolBox::GetItemRect( ToolBoxItemId nItemId
)
840 if ( mbCalc
|| mbFormat
)
843 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
844 return GetItemPosRect( nPos
);
847 tools::Rectangle
ToolBox::GetItemPosRect( ImplToolItems::size_type nPos
)
849 if ( mbCalc
|| mbFormat
)
852 if ( nPos
< mpData
->m_aItems
.size() )
853 return mpData
->m_aItems
[nPos
].maRect
;
855 return tools::Rectangle();
858 tools::Rectangle
const & ToolBox::GetOverflowRect() const
860 return mpData
->maMenubuttonItem
.maRect
;
863 bool ToolBox::ImplHasExternalMenubutton() const
865 // check if the borderwindow (i.e. the decoration) provides the menu button
867 if( ImplIsFloatingMode() )
869 // custom menu is placed in the decoration
870 ImplBorderWindow
*pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
871 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
877 void ToolBox::SetItemBits( ToolBoxItemId nItemId
, ToolBoxItemBits nBits
)
879 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
881 if ( nPos
< GetItemCount() )
883 ToolBoxItemBits nOldBits
= mpData
->m_aItems
[nPos
].mnBits
;
884 mpData
->m_aItems
[nPos
].mnBits
= nBits
;
885 nBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
886 nOldBits
&= ToolBoxItemBits::LEFT
| ToolBoxItemBits::AUTOSIZE
| ToolBoxItemBits::DROPDOWN
;
887 // trigger reformat when the item width has changed (dropdown arrow)
888 bool bFormat
= ToolBoxItemBits(nBits
& ToolBoxItemBits::DROPDOWN
) != ToolBoxItemBits(nOldBits
& ToolBoxItemBits::DROPDOWN
);
889 if ( nBits
!= nOldBits
)
890 ImplInvalidate( true, bFormat
);
894 void ToolBox::SetItemWindowNonInteractive(ToolBoxItemId nItemId
, bool bNonInteractive
)
896 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
898 if ( nPos
< GetItemCount() )
900 mpData
->m_aItems
[nPos
].mbNonInteractiveWindow
= bNonInteractive
;
904 ToolBoxItemBits
ToolBox::GetItemBits( ToolBoxItemId nItemId
) const
906 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
909 return pItem
->mnBits
;
911 return ToolBoxItemBits::NONE
;
914 void ToolBox::SetItemExpand( ToolBoxItemId nItemId
, bool bExpand
)
916 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
920 if (pItem
->mbExpand
!= bExpand
)
922 pItem
->mbExpand
= bExpand
;
923 ImplInvalidate(true, true);
927 void ToolBox::SetItemData( ToolBoxItemId nItemId
, void* pNewData
)
929 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
931 if ( nPos
< mpData
->m_aItems
.size() )
933 mpData
->m_aItems
[nPos
].mpUserData
= pNewData
;
934 ImplUpdateItem( nPos
);
938 void* ToolBox::GetItemData( ToolBoxItemId nItemId
) const
940 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
943 return pItem
->mpUserData
;
948 static Image
ImplMirrorImage( const Image
& rImage
)
950 BitmapEx
aMirrBitmapEx( rImage
.GetBitmapEx() );
952 aMirrBitmapEx
.Mirror( BmpMirrorFlags::Horizontal
);
954 return Image( aMirrBitmapEx
);
957 static Image
ImplRotImage( const Image
& rImage
, Degree10 nAngle10
)
959 BitmapEx
aRotBitmapEx( rImage
.GetBitmapEx() );
961 aRotBitmapEx
.Rotate( nAngle10
, COL_WHITE
);
963 return Image( aRotBitmapEx
);
966 void ToolBox::SetItemImage( ToolBoxItemId nItemId
, const Image
& rImage
)
968 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
970 if ( nPos
== ITEM_NOTFOUND
)
973 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
974 Size aOldSize
= pItem
->maImage
.GetSizePixel();
976 pItem
->maImage
= pItem
->mbMirrorMode
? ImplMirrorImage(rImage
) : rImage
;
977 if (pItem
->mnImageAngle
!= 0_deg10
)
978 pItem
->maImage
= ImplRotImage(pItem
->maImage
, pItem
->mnImageAngle
);
980 // only once all is calculated, do extra work
983 if (aOldSize
!= pItem
->maImage
.GetSizePixel())
984 ImplInvalidate( true );
986 ImplUpdateItem( nPos
);
990 void ToolBox::SetItemImageAngle( ToolBoxItemId nItemId
, Degree10 nAngle10
)
992 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
994 if ( nPos
== ITEM_NOTFOUND
)
997 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
998 pItem
->mnImageAngle
= nAngle10
;
1001 void ToolBox::SetItemImageMirrorMode( ToolBoxItemId nItemId
, bool bMirror
)
1003 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1005 if ( nPos
== ITEM_NOTFOUND
)
1008 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1009 pItem
->mbMirrorMode
= bMirror
;
1012 Image
ToolBox::GetItemImage(ToolBoxItemId nItemId
) const
1014 ImplToolItem
* pItem
= ImplGetItem(nItemId
);
1015 return pItem
? pItem
->maImage
: Image();
1018 void ToolBox::SetItemText( ToolBoxItemId nItemId
, const OUString
& rText
)
1020 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1022 if ( nPos
== ITEM_NOTFOUND
)
1025 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1026 // only once all is calculated, do extra work
1028 ((meButtonType
!= ButtonType::SYMBOLONLY
) || !pItem
->maImage
) )
1030 tools::Long nOldWidth
= GetOutDev()->GetCtrlTextWidth( pItem
->maText
);
1031 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1032 mpData
->ImplClearLayoutData();
1033 if ( nOldWidth
!= GetOutDev()->GetCtrlTextWidth( pItem
->maText
) )
1034 ImplInvalidate( true );
1036 ImplUpdateItem( nPos
);
1039 pItem
->maText
= MnemonicGenerator::EraseAllMnemonicChars(rText
);
1041 // Notify button changed event to prepare accessibility bridge
1042 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1045 CallEventListeners( VclEventId::ToolboxItemTextChanged
, reinterpret_cast< void* >( nPos
) );
1048 const OUString
& ToolBox::GetItemText( ToolBoxItemId nItemId
) const
1051 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1055 return pItem
->maText
;
1058 void ToolBox::SetItemWindow( ToolBoxItemId nItemId
, vcl::Window
* pNewWindow
)
1060 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1062 if ( nPos
!= ITEM_NOTFOUND
)
1064 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1065 pItem
->mpWindow
= pNewWindow
;
1068 ImplInvalidate( true );
1069 CallEventListeners( VclEventId::ToolboxItemWindowChanged
, reinterpret_cast< void* >( nPos
) );
1073 vcl::Window
* ToolBox::GetItemWindow( ToolBoxItemId nItemId
) const
1075 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1078 return pItem
->mpWindow
;
1083 void ToolBox::EndSelection()
1089 if (mnCurPos
!= ITEM_NOTFOUND
)
1090 InvalidateItem(mnCurPos
);
1092 if (IsMouseCaptured())
1097 mnCurPos
= ITEM_NOTFOUND
;
1098 mnCurItemId
= ToolBoxItemId(0);
1099 mnDownItemId
= ToolBoxItemId(0);
1100 mnMouseModifier
= 0;
1103 void ToolBox::SetItemDown( ToolBoxItemId nItemId
, bool bDown
)
1105 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1107 if ( nPos
== ITEM_NOTFOUND
)
1112 if ( nPos
!= mnCurPos
)
1115 InvalidateItem(mnCurPos
);
1116 GetOutDev()->Flush();
1121 if ( nPos
== mnCurPos
)
1123 InvalidateItem(mnCurPos
);
1124 GetOutDev()->Flush();
1125 mnCurPos
= ITEM_NOTFOUND
;
1133 if (IsMouseCaptured())
1138 mnCurItemId
= ToolBoxItemId(0);
1139 mnDownItemId
= ToolBoxItemId(0);
1140 mnMouseModifier
= 0;
1143 void ToolBox::SetItemState( ToolBoxItemId nItemId
, TriState eState
)
1145 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1147 if ( nPos
== ITEM_NOTFOUND
)
1150 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1152 // the state has changed
1153 if ( pItem
->meState
== eState
)
1156 // if RadioCheck, un-check the previous
1157 if ( (eState
== TRISTATE_TRUE
) && (pItem
->mnBits
& ToolBoxItemBits::AUTOCHECK
) &&
1158 (pItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
) )
1160 ImplToolItem
* pGroupItem
;
1161 ImplToolItems::size_type nGroupPos
;
1162 ImplToolItems::size_type nItemCount
= GetItemCount();
1167 pGroupItem
= &mpData
->m_aItems
[nGroupPos
-1];
1168 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1170 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1171 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1179 while ( nGroupPos
< nItemCount
)
1181 pGroupItem
= &mpData
->m_aItems
[nGroupPos
];
1182 if ( pGroupItem
->mnBits
& ToolBoxItemBits::RADIOCHECK
)
1184 if ( pGroupItem
->meState
!= TRISTATE_FALSE
)
1185 SetItemState( pGroupItem
->mnId
, TRISTATE_FALSE
);
1193 pItem
->meState
= eState
;
1194 ImplUpdateItem( nPos
);
1196 // Notify button changed event to prepare accessibility bridge
1197 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1199 // Call accessible listener to notify state_changed event
1200 CallEventListeners( VclEventId::ToolboxItemUpdated
, reinterpret_cast< void* >(nPos
) );
1203 TriState
ToolBox::GetItemState( ToolBoxItemId nItemId
) const
1205 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1208 return pItem
->meState
;
1210 return TRISTATE_FALSE
;
1213 void ToolBox::EnableItem( ToolBoxItemId nItemId
, bool bEnable
)
1215 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1217 if ( nPos
== ITEM_NOTFOUND
)
1220 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1221 if ( pItem
->mbEnabled
== bEnable
)
1224 pItem
->mbEnabled
= bEnable
;
1226 // if existing, also redraw the window
1227 if ( pItem
->mpWindow
)
1228 pItem
->mpWindow
->Enable( pItem
->mbEnabled
);
1231 ImplUpdateItem( nPos
);
1233 ImplUpdateInputEnable();
1235 // Notify button changed event to prepare accessibility bridge
1236 CallEventListeners( VclEventId::ToolboxButtonStateChanged
, reinterpret_cast< void* >( nPos
) );
1238 CallEventListeners( bEnable
? VclEventId::ToolboxItemEnabled
: VclEventId::ToolboxItemDisabled
, reinterpret_cast< void* >( nPos
) );
1241 bool ToolBox::IsItemEnabled( ToolBoxItemId nItemId
) const
1243 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1246 return pItem
->mbEnabled
;
1251 void ToolBox::ShowItem( ToolBoxItemId nItemId
, bool bVisible
)
1253 ImplToolItems::size_type nPos
= GetItemPos( nItemId
);
1254 mpData
->ImplClearLayoutData();
1256 if ( nPos
!= ITEM_NOTFOUND
)
1258 ImplToolItem
* pItem
= &mpData
->m_aItems
[nPos
];
1259 if ( pItem
->mbVisible
!= bVisible
)
1261 pItem
->mbVisible
= bVisible
;
1267 bool ToolBox::IsItemClipped( ToolBoxItemId nItemId
) const
1269 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1272 return pItem
->IsClipped();
1277 bool ToolBox::IsItemVisible( ToolBoxItemId nItemId
) const
1279 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1282 return pItem
->mbVisible
;
1287 bool ToolBox::IsItemReallyVisible( ToolBoxItemId nItemId
) const
1289 // is the item on the visible area of the toolbox?
1291 tools::Rectangle
aRect( mnLeftBorder
, mnTopBorder
, mnDX
-mnRightBorder
, mnDY
-mnBottomBorder
);
1292 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1294 if ( pItem
&& pItem
->mbVisible
&&
1295 !pItem
->maRect
.IsEmpty() && aRect
.Overlaps( pItem
->maRect
) )
1303 void ToolBox::SetItemCommand(ToolBoxItemId nItemId
, const OUString
& rCommand
)
1305 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1308 pItem
->maCommandStr
= rCommand
;
1311 OUString
ToolBox::GetItemCommand( ToolBoxItemId nItemId
) const
1313 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1316 return pItem
->maCommandStr
;
1321 void ToolBox::SetQuickHelpText( ToolBoxItemId nItemId
, const OUString
& rText
)
1323 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1326 pItem
->maQuickHelpText
= rText
;
1329 OUString
ToolBox::GetQuickHelpText( ToolBoxItemId nItemId
) const
1331 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1334 return pItem
->maQuickHelpText
;
1339 void ToolBox::SetHelpText( ToolBoxItemId nItemId
, const OUString
& rText
)
1341 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1344 pItem
->maHelpText
= rText
;
1347 const OUString
& ToolBox::GetHelpText( ToolBoxItemId nItemId
) const
1349 return ImplGetHelpText( nItemId
);
1352 void ToolBox::SetHelpId( ToolBoxItemId nItemId
, const OUString
& rHelpId
)
1354 ImplToolItem
* pItem
= ImplGetItem( nItemId
);
1357 pItem
->maHelpId
= rHelpId
;
1360 // disable key input if all items are disabled
1361 void ToolBox::ImplUpdateInputEnable()
1363 mpData
->mbKeyInputDisabled
= std::none_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1364 [](const ImplToolItem
& rItem
) {
1365 // at least one useful entry
1366 return rItem
.mbEnabled
;
1370 void ToolBox::ImplFillLayoutData()
1372 mpData
->m_pLayoutData
.emplace();
1374 ImplToolItems::size_type nCount
= mpData
->m_aItems
.size();
1375 for( ImplToolItems::size_type i
= 0; i
< nCount
; i
++ )
1377 ImplToolItem
* pItem
= &mpData
->m_aItems
[i
];
1379 // only draw, if the rectangle is within PaintRectangle
1380 if (!pItem
->maRect
.IsEmpty())
1385 OUString
ToolBox::GetDisplayText() const
1387 if( ! mpData
->m_pLayoutData
)
1388 const_cast<ToolBox
*>(this)->ImplFillLayoutData();
1389 return mpData
->m_pLayoutData
? mpData
->m_pLayoutData
->m_aDisplayText
: OUString();
1392 tools::Rectangle
ToolBox::GetCharacterBounds( ToolBoxItemId nItemID
, tools::Long nIndex
)
1394 tools::Long nItemIndex
= -1;
1395 if( ! mpData
->m_pLayoutData
)
1396 ImplFillLayoutData();
1397 if( mpData
->m_pLayoutData
)
1399 for( size_t i
= 0; i
< mpData
->m_pLayoutData
->m_aLineItemIds
.size(); i
++ )
1401 if( mpData
->m_pLayoutData
->m_aLineItemIds
[i
] == nItemID
)
1403 nItemIndex
= mpData
->m_pLayoutData
->m_aLineIndices
[i
];
1408 return (mpData
->m_pLayoutData
&& nItemIndex
!= -1) ? mpData
->m_pLayoutData
->GetCharacterBounds( nItemIndex
+nIndex
) : tools::Rectangle();
1411 tools::Long
ToolBox::GetIndexForPoint( const Point
& rPoint
, ToolBoxItemId
& rItemID
)
1413 tools::Long nIndex
= -1;
1414 rItemID
= ToolBoxItemId(0);
1415 if( ! mpData
->m_pLayoutData
)
1416 ImplFillLayoutData();
1417 if( mpData
->m_pLayoutData
)
1419 nIndex
= mpData
->m_pLayoutData
->GetIndexForPoint( rPoint
);
1420 for( size_t i
= 0; i
< mpData
->m_pLayoutData
->m_aLineIndices
.size(); i
++ )
1422 if( mpData
->m_pLayoutData
->m_aLineIndices
[i
] <= nIndex
&&
1423 (i
== mpData
->m_pLayoutData
->m_aLineIndices
.size()-1 || mpData
->m_pLayoutData
->m_aLineIndices
[i
+1] > nIndex
) )
1425 rItemID
= mpData
->m_pLayoutData
->m_aLineItemIds
[i
];
1433 void ToolBox::SetDropdownClickHdl( const Link
<ToolBox
*, void>& rLink
)
1435 if (mpData
!= nullptr) {
1436 mpData
->maDropdownClickHdl
= rLink
;
1440 void ToolBox::SetMenuType( ToolBoxMenuType aType
)
1442 if( aType
== mpData
->maMenuType
)
1445 mpData
->maMenuType
= aType
;
1446 if( IsFloatingMode() )
1448 // the menu button may have to be moved into the decoration which changes the layout
1449 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1451 pWrapper
->ShowMenuTitleButton( bool( aType
& ToolBoxMenuType::Customize
) );
1455 ImplSetMinMaxFloatSize();
1459 // trigger redraw of menu button
1460 if( !mpData
->maMenubuttonItem
.maRect
.IsEmpty() )
1461 Invalidate(mpData
->maMenubuttonItem
.maRect
);
1465 ToolBoxMenuType
ToolBox::GetMenuType() const
1467 return mpData
->maMenuType
;
1470 bool ToolBox::IsMenuEnabled() const
1472 return mpData
->maMenuType
!= ToolBoxMenuType::NONE
;
1475 PopupMenu
* ToolBox::GetMenu() const
1477 return mpData
== nullptr ? nullptr : mpData
->mpMenu
;
1480 void ToolBox::SetMenuExecuteHdl( const Link
<ToolBox
*, void>& rLink
)
1482 mpData
->maMenuButtonHdl
= rLink
;
1485 bool ToolBox::ImplHasClippedItems()
1487 // are any items currently clipped ?
1489 return std::any_of(mpData
->m_aItems
.begin(), mpData
->m_aItems
.end(),
1490 [](const ImplToolItem
& rItem
) { return rItem
.IsClipped(); });
1495 MenuItemBits
ConvertBitsFromToolBoxToMenu(ToolBoxItemBits nToolItemBits
)
1497 MenuItemBits nMenuItemBits
= MenuItemBits::NONE
;
1498 if ((nToolItemBits
& ToolBoxItemBits::CHECKABLE
) ||
1499 (nToolItemBits
& ToolBoxItemBits::DROPDOWN
))
1501 nMenuItemBits
|= MenuItemBits::CHECKABLE
;
1503 return nMenuItemBits
;
1507 void ToolBox::UpdateCustomMenu()
1509 // fill clipped items into menu
1510 PopupMenu
*pMenu
= GetMenu();
1513 // add menu items: first the overflow items, then hidden items, both in the
1514 // order they would usually appear in the toolbar. Separators that would be
1515 // in the toolbar are ignored as they would introduce too much clutter,
1516 // instead we have a single separator to help distinguish between overflow
1517 // and hidden items.
1518 if ( mpData
->m_aItems
.empty() )
1521 // nStartPos will hold the number of clipped items appended from first loop
1522 for ( const auto& rItem
: mpData
->m_aItems
)
1524 if( rItem
.IsClipped() )
1526 sal_uInt16 id
= sal_uInt16(rItem
.mnId
) + TOOLBOX_MENUITEM_START
;
1527 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1528 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1529 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1530 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1531 pMenu
->CheckItem ( id
, rItem
.meState
== TRISTATE_TRUE
);
1535 // add a separator below the inserted clipped-items
1536 pMenu
->InsertSeparator();
1538 // now append the items that are explicitly disabled
1539 for ( const auto& rItem
: mpData
->m_aItems
)
1541 if( rItem
.IsItemHidden() )
1543 sal_uInt16 id
= sal_uInt16(rItem
.mnId
) + TOOLBOX_MENUITEM_START
;
1544 MenuItemBits nMenuItemBits
= ConvertBitsFromToolBoxToMenu(rItem
.mnBits
);
1545 pMenu
->InsertItem( id
, rItem
.maText
, rItem
.maImage
, nMenuItemBits
);
1546 pMenu
->SetItemCommand( id
, rItem
.maCommandStr
);
1547 pMenu
->EnableItem( id
, rItem
.mbEnabled
);
1548 pMenu
->CheckItem( id
, rItem
.meState
== TRISTATE_TRUE
);
1553 IMPL_LINK( ToolBox
, ImplCustomMenuListener
, VclMenuEvent
&, rEvent
, void )
1555 if( rEvent
.GetMenu() == GetMenu() && rEvent
.GetId() == VclEventId::MenuSelect
)
1557 sal_uInt16 id
= GetMenu()->GetItemId( rEvent
.GetItemPos() );
1558 if( id
>= TOOLBOX_MENUITEM_START
)
1559 TriggerItem( ToolBoxItemId(id
- TOOLBOX_MENUITEM_START
) );
1563 void ToolBox::ExecuteCustomMenu( const tools::Rectangle
& rRect
)
1565 if ( !IsMenuEnabled() || ImplIsInPopupMode() )
1570 if( GetMenuType() & ToolBoxMenuType::Customize
)
1571 // call button handler to allow for menu customization
1572 mpData
->maMenuButtonHdl
.Call( this );
1574 GetMenu()->AddEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1576 // make sure all disabled entries will be shown
1577 GetMenu()->SetMenuFlags(
1578 GetMenu()->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries
);
1580 // toolbox might be destroyed during execute
1581 bool bBorderDel
= false;
1583 VclPtr
<vcl::Window
> pWin
= this;
1584 tools::Rectangle aMenuRect
= rRect
;
1585 VclPtr
<ImplBorderWindow
> pBorderWin
;
1586 if( aMenuRect
.IsEmpty() && IsFloatingMode() )
1588 // custom menu is placed in the decoration
1589 pBorderWin
= dynamic_cast<ImplBorderWindow
*>( GetWindow( GetWindowType::Border
) );
1590 if( pBorderWin
&& !pBorderWin
->GetMenuRect().IsEmpty() )
1593 aMenuRect
= pBorderWin
->GetMenuRect();
1598 sal_uInt16 uId
= GetMenu()->Execute( pWin
, tools::Rectangle( ImplGetPopupPosition( aMenuRect
), Size() ),
1599 PopupMenuFlags::ExecuteDown
| PopupMenuFlags::NoMouseUpClose
);
1601 if ( pWin
->isDisposed() )
1605 GetMenu()->RemoveEventListener( LINK( this, ToolBox
, ImplCustomMenuListener
) );
1608 if( pBorderWin
->isDisposed() )
1612 pWin
->Invalidate( aMenuRect
);
1615 GrabFocusToDocument();
1618 // checks override first, useful during calculation of sizes
1619 bool ToolBox::ImplIsFloatingMode() const
1621 SAL_WARN_IF( mpData
->mbAssumeDocked
&& mpData
->mbAssumeFloating
, "vcl",
1622 "cannot assume docked and floating" );
1624 if( mpData
->mbAssumeDocked
)
1626 else if( mpData
->mbAssumeFloating
)
1629 return IsFloatingMode();
1632 // checks override first, useful during calculation of sizes
1633 bool ToolBox::ImplIsInPopupMode() const
1635 if( mpData
->mbAssumePopupMode
)
1639 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1640 return ( pWrapper
&& pWrapper
->GetFloatingWindow() && static_cast<FloatingWindow
*>(pWrapper
->GetFloatingWindow())->IsInPopupMode() );
1644 void ToolBox::Lock( bool bLock
)
1646 ImplDockingWindowWrapper
*pWrapper
= ImplGetDockingManager()->GetDockingWindowWrapper( this );
1649 if( mpData
->mbIsLocked
!= bLock
)
1651 mpData
->mbIsLocked
= bLock
;
1652 if( !ImplIsFloatingMode() )
1656 SetSizePixel( CalcWindowSizePixel(1) );
1662 bool ToolBox::AlwaysLocked()
1664 // read config item to determine toolbox behaviour, used for subtoolbars
1666 static int nAlwaysLocked
= -1;
1668 if( nAlwaysLocked
== -1 )
1670 nAlwaysLocked
= 0; // ask configuration only once
1672 utl::OConfigurationNode aNode
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1673 comphelper::getProcessComponentContext(),
1674 "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ); // note: case sensitive !
1675 if ( aNode
.isValid() )
1677 // feature enabled ?
1678 bool bStatesEnabled
= bool();
1679 css::uno::Any aValue
= aNode
.getNodeValue( "StatesEnabled" );
1680 if( aValue
>>= bStatesEnabled
)
1682 if( bStatesEnabled
)
1684 // now read the locking state
1685 utl::OConfigurationNode aNode2
= utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
1686 comphelper::getProcessComponentContext(),
1687 "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ); // note: case sensitive !
1689 bool bLocked
= bool();
1690 css::uno::Any aValue2
= aNode2
.getNodeValue( "Locked" );
1691 if( aValue2
>>= bLocked
)
1692 nAlwaysLocked
= bLocked
? 1 : 0;
1698 return nAlwaysLocked
== 1;
1701 bool ToolBox::WillUsePopupMode() const
1703 return mpData
->mbWillUsePopupMode
;
1706 void ToolBox::WillUsePopupMode( bool b
)
1708 mpData
->mbWillUsePopupMode
= b
;
1711 void ToolBox::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
1713 DockingWindow::DumpAsPropertyTree(rJsonWriter
);
1715 auto childrenNode
= rJsonWriter
.startArray("children");
1716 for (ToolBox::ImplToolItems::size_type i
= 0; i
< GetItemCount(); ++i
)
1718 auto childNode
= rJsonWriter
.startStruct();
1719 ToolBoxItemId nId
= GetItemId(i
);
1721 vcl::Window
* pWindow
= GetItemWindow(nId
);
1724 pWindow
->DumpAsPropertyTree(rJsonWriter
);
1728 OUString sCommand
= GetItemCommand(nId
);
1729 rJsonWriter
.put("type", "toolitem");
1730 rJsonWriter
.put("text", GetItemText(nId
));
1731 rJsonWriter
.put("command", sCommand
);
1732 if (IsItemChecked(nId
))
1733 rJsonWriter
.put("selected", true);
1734 if (!IsItemVisible(nId
))
1735 rJsonWriter
.put("visible", false);
1736 if (GetItemBits(nId
) & ToolBoxItemBits::DROPDOWN
)
1737 rJsonWriter
.put("dropdown", true);
1738 if (!IsItemEnabled(nId
))
1739 rJsonWriter
.put("enabled", false);
1741 Image aImage
= GetItemImage(nId
);
1742 if (!sCommand
.startsWith(".uno:") && !!aImage
)
1744 SvMemoryStream
aOStm(6535, 6535);
1745 if(GraphicConverter::Export(aOStm
, aImage
.GetBitmapEx(), ConvertDataFormat::PNG
) == ERRCODE_NONE
)
1747 css::uno::Sequence
<sal_Int8
> aSeq( static_cast<sal_Int8
const *>(aOStm
.GetData()), aOStm
.Tell());
1748 OStringBuffer
aBuffer("data:image/png;base64,");
1749 ::comphelper::Base64::encode(aBuffer
, aSeq
);
1750 rJsonWriter
.put("image", aBuffer
);
1757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */