build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / toolbox2.cxx
blob63459109109550883f420fb407c2dd1efea501fc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include <tools/rc.h>
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>
37 #include <svdata.hxx>
38 #include <brdwin.hxx>
39 #include <toolbox.h>
41 #include <unotools/confignode.hxx>
43 using namespace vcl;
45 #define TB_SEP_SIZE 8 // Separator size
48 ImplToolBoxPrivateData::ImplToolBoxPrivateData() :
49 m_pLayoutData( nullptr )
51 meButtonSize = ToolBoxButtonSize::DontCare;
52 mpMenu = VclPtr<PopupMenu>::Create();
53 mnEventId = nullptr;
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;
60 mbIsLocked = false;
61 mbNativeButtons = false;
62 mbIsPaintLocked = false;
63 mbAssumeDocked = false;
64 mbAssumePopupMode = false;
65 mbAssumeFloating = false;
66 mbKeyInputDisabled = false;
67 mbMenubuttonSelected = false;
68 mbPageScroll = false;
69 mbWillUsePopupMode = false;
70 mbDropDownByKeyboard = false;
73 ImplToolBoxPrivateData::~ImplToolBoxPrivateData()
75 delete m_pLayoutData;
76 mpMenu.disposeAndClear();
79 void ImplToolItem::init(sal_uInt16 nItemId, ToolBoxItemBits nItemBits,
80 bool bEmptyBtn)
82 mnId = nItemId;
83 mpWindow = nullptr;
84 mpUserData = nullptr;
85 meType = ToolBoxItemType::BUTTON;
86 mnBits = nItemBits;
87 meState = TRISTATE_FALSE;
88 mbEnabled = true;
89 mbVisible = true;
90 mbEmptyBtn = bEmptyBtn;
91 mbShowWindow = false;
92 mbBreak = false;
93 mnSepSize = TB_SEP_SIZE;
94 mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
95 mnImageAngle = 0;
96 mbMirrorMode = false;
97 mbVisibleText = false;
98 mbExpand = false;
101 ImplToolItem::ImplToolItem()
103 init(0, ToolBoxItemBits::NONE, true);
106 ImplToolItem::ImplToolItem( sal_uInt16 nItemId, const Image& rImage,
107 ToolBoxItemBits nItemBits ) :
108 maImage( rImage )
110 init(nItemId, nItemBits, false);
113 ImplToolItem::ImplToolItem( sal_uInt16 nItemId, const OUString& rText,
114 ToolBoxItemBits nItemBits ) :
115 maText( rText )
117 init(nItemId, nItemBits, false);
120 ImplToolItem::ImplToolItem( sal_uInt16 nItemId, const Image& rImage,
121 const OUString& rText, ToolBoxItemBits nItemBits ) :
122 maImage( rImage ),
123 maText( rText )
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) )
135 aSize = maItemSize;
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
145 // clipped.
146 bCheckMaxWidth = false;
148 if ( !bCheckMaxWidth || (aWinSize.Width() <= maxWidth) )
150 aSize.Width() = aWinSize.Width();
151 aSize.Height() = aWinSize.Height();
152 mbShowWindow = true;
154 else
156 if ( mbEmptyBtn )
158 aSize.Width() = 0;
159 aSize.Height() = 0;
164 else if ( meType == ToolBoxItemType::SEPARATOR )
166 if ( bHorz )
168 aSize.Width() = mnSepSize;
169 aSize.Height() = rDefaultSize.Height();
171 else
173 aSize.Width() = rDefaultSize.Width();
174 aSize.Height() = mnSepSize;
177 else if ( meType == ToolBoxItemType::BREAK )
179 aSize.Width() = 0;
180 aSize.Height() = 0;
183 return aSize;
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;
192 return;
195 bool bHasImage;
196 bool bHasText;
198 // check for image and/or text
199 if ( !(maImage) )
200 bHasImage = false;
201 else
202 bHasImage = true;
203 if ( maText.isEmpty() )
204 bHasText = false;
205 else
206 bHasText = true;
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 )
215 rbImage = true;
216 rbText = false;
218 else
220 rbImage = false;
221 rbText = true;
224 else if ( eButtonType == ButtonType::TEXT ) // drawing text only
226 if( bHasText || !bHasImage )
228 rbImage = false;
229 rbText = true;
231 else
233 rbImage = true;
234 rbText = false;
237 else // drawing icons and text both
239 rbImage = true;
240 rbText = true;
244 Rectangle ImplToolItem::GetDropDownRect( bool bHorz ) const
246 Rectangle aRect;
247 if( (mnBits & ToolBoxItemBits::DROPDOWN) && !maRect.IsEmpty() )
249 aRect = maRect;
250 if( mbVisibleText && !bHorz )
251 // item will be rotated -> place dropdown to the bottom
252 aRect.Top() = aRect.Bottom() - mnDropDownArrowWidth;
253 else
254 // place dropdown to the right
255 aRect.Left() = aRect.Right() - mnDropDownArrowWidth;
257 return aRect;
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();
274 if ( bNewCalc )
275 mbCalc = true;
277 if ( bFullPaint )
279 mbFormat = true;
281 // do we need to redraw?
282 if ( IsReallyVisible() && IsUpdateMode() )
284 Invalidate( Rectangle( mnLeftBorder, mnTopBorder,
285 mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) );
286 mpIdle->Stop();
289 else
291 if ( !mbFormat )
293 mbFormat = true;
295 // do we need to redraw?
296 if ( IsReallyVisible() && IsUpdateMode() )
297 mpIdle->Start();
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 ) );
315 else
317 if ( !mbFormat )
319 // #i52217# no immediate draw as this might lead to paint problems
320 Invalidate( mpData->m_aItems[nIndex].maRect );
322 else
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()
342 mnActivateCount++;
343 CallEventListeners( VCLEVENT_TOOLBOX_ACTIVATE );
344 maActivateHdl.Call( this );
347 void ToolBox::Deactivate()
349 mnActivateCount--;
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() )
367 return;
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 );
389 // Notify
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,
395 sal_uInt16 nPos )
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 );
409 // Notify
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 );
427 // Notify
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 );
455 if ( pItem )
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
467 ImplToolItem aItem;
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();
475 if ( pWindow )
476 pWindow->Hide();
478 ImplInvalidate( true );
480 // Notify
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
488 ImplToolItem aItem;
489 aItem.meType = ToolBoxItemType::SPACE;
490 aItem.mbEnabled = false;
491 mpData->m_aItems.push_back( aItem );
492 mpData->ImplClearLayoutData();
494 ImplInvalidate();
496 // Notify
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
504 ImplToolItem aItem;
505 aItem.meType = ToolBoxItemType::SEPARATOR;
506 aItem.mbEnabled = false;
507 if ( nPixSize )
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();
512 ImplInvalidate();
514 // Notify
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
522 ImplToolItem aItem;
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();
528 ImplInvalidate();
530 // Notify
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() )
539 bool bMustCalc;
540 if ( mpData->m_aItems[nPos].meType == ToolBoxItemType::BUTTON )
541 bMustCalc = true;
542 else
543 bMustCalc = false;
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 = 0;
554 if ( mpData->m_aItems[nPos].mnId == mnHighItemId )
555 mnHighItemId = 0;
557 ImplInvalidate( bMustCalc );
559 mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos );
560 mpData->ImplClearLayoutData();
562 // Notify
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 );
574 // found item
575 if ( nPos != TOOLBOX_ITEM_NOTFOUND )
577 // push ToolBox item onto the list
578 ImplToolItem aNewItem = rToolBox.mpData->m_aItems[nPos];
579 // reset state
580 aNewItem.mpWindow = nullptr;
581 aNewItem.mbShowWindow = false;
583 mpData->m_aItems.push_back( aNewItem );
584 mpData->ImplClearLayoutData();
585 // redraw ToolBox
586 ImplInvalidate();
588 // Notify
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
600 mnCurItemId = 0;
601 mnHighItemId = 0;
603 ImplInvalidate( true, true );
605 // Notify
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;
626 mbCalc = true;
627 mbFormat = true;
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 )
665 meAlign = eNewAlign;
667 if ( !ImplIsFloatingMode() )
669 // set horizontal/vertical alignment
670 if ( (eNewAlign == WindowAlign::Left) || (eNewAlign == WindowAlign::Right) )
671 mbHorz = false;
672 else
673 mbHorz = true;
675 // Update the background according to Persona if necessary
676 ImplInitSettings( false, false, true );
678 // redraw everything, as the border has changed
679 mbCalc = true;
680 mbFormat = true;
681 if ( IsReallyVisible() && IsUpdateMode() )
682 Invalidate();
687 void ToolBox::SetLineCount( sal_uInt16 nNewLines )
689 if ( !nNewLines )
690 nNewLines = 1;
692 if ( mnLines != nNewLines )
694 mnLines = nNewLines;
696 // better redraw everything, as otherwise there might be problems
697 // with regions that were copied with CopyBits
698 Invalidate();
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
719 if (mpData)
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;
733 sal_uInt16 nPos = 0;
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
740 nRet = nPos;
741 break;
744 ++it;
745 ++nPos;
748 return nRet;
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() )
762 // is it this item?
763 if ( it->maRect.IsInside( rPos ) )
765 if ( it->meType == ToolBoxItemType::BUTTON )
766 return it->mnId;
767 else
768 return 0;
771 ++it;
774 return 0;
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;
785 else
786 return Size();
789 sal_uInt16 ToolBox::GetItemId(const OUString &rCommand) const
791 if (!mpData)
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)
797 return it->mnId;
800 return 0;
803 Point ToolBox::ImplGetPopupPosition( const Rectangle& rRect, const Size& rSize ) const
805 Point aPos;
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
816 switch( meAlign )
818 case WindowAlign::Top:
819 aPos = rRect.BottomLeft();
820 aPos.Y()++;
821 devPos = OutputToAbsoluteScreenPixel( aPos );
822 if( devPos.Y() + rSize.Height() >= aScreen.Bottom() )
823 aPos.Y() = rRect.Top() - rSize.Height();
824 break;
825 case WindowAlign::Bottom:
826 aPos = rRect.TopLeft();
827 aPos.Y()--;
828 devPos = OutputToAbsoluteScreenPixel( aPos );
829 if( devPos.Y() - rSize.Height() > aScreen.Top() )
830 aPos.Y() -= rSize.Height();
831 else
832 aPos.Y() = rRect.Bottom();
833 break;
834 case WindowAlign::Left:
835 aPos = rRect.TopRight();
836 aPos.X()++;
837 devPos = OutputToAbsoluteScreenPixel( aPos );
838 if( devPos.X() + rSize.Width() >= aScreen.Right() )
839 aPos.X() = rRect.Left() - rSize.Width();
840 break;
841 case WindowAlign::Right:
842 aPos = rRect.TopLeft();
843 aPos.X()--;
844 devPos = OutputToAbsoluteScreenPixel( aPos );
845 if( devPos.X() - rSize.Width() > aScreen.Left() )
846 aPos.X() -= rSize.Width();
847 else
848 aPos.X() = rRect.Right();
849 break;
850 default:
851 break;
854 return aPos;
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;
873 else
874 return Rectangle();
877 bool ToolBox::ImplHasExternalMenubutton()
879 // check if the borderwindow (i.e. the decoration) provides the menu button
880 bool bRet = false;
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() )
886 bRet = true;
888 return bRet;
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 );
912 if ( pItem )
913 return pItem->mnBits;
914 else
915 return ToolBoxItemBits::NONE;
918 void ToolBox::SetItemExpand( sal_uInt16 nItemId, bool bExpand )
920 ImplToolItem* pItem = ImplGetItem( nItemId );
921 if (!pItem)
922 return;
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 );
946 if ( pItem )
947 return pItem->mpUserData;
948 else
949 return nullptr;
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
964 if (!mbCalc)
966 if (aOldSize != pItem->maImage.GetSizePixel())
967 ImplInvalidate( true );
968 else
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++ )
981 Image aImage;
982 if ( mpData->m_aItems[i].mnId )
983 aImage = maImageList.GetImage( mpData->m_aItems[i].mnId );
984 if( !!aImage )
985 SetItemImage( mpData->m_aItems[i].mnId, aImage );
989 static Image ImplRotImage( const Image& rImage, long nAngle10 )
991 Image aRet;
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 );
1018 if (!mbCalc)
1020 if (aOldSize != pItem->maImage.GetSizePixel())
1021 ImplInvalidate(true);
1022 else
1023 ImplUpdateItem(nPos);
1028 static Image ImplMirrorImage( const Image& rImage )
1030 Image aRet;
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);
1055 if (!mbCalc)
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
1075 if ( !mbCalc &&
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 );
1083 else
1084 ImplUpdateItem( nPos );
1086 else
1087 pItem->maText = MnemonicGenerator::EraseAllMnemonicChars(rText);
1089 // Notify button changed event to prepare accessibility bridge
1090 CallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) );
1092 // Notify
1093 CallEventListeners( VCLEVENT_TOOLBOX_ITEMTEXTCHANGED, reinterpret_cast< void* >( nPos ) );
1097 const OUString& ToolBox::GetItemText( sal_uInt16 nItemId ) const
1100 ImplToolItem* pItem = ImplGetItem( nItemId );
1102 assert( pItem );
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;
1115 if ( pNewWindow )
1116 pNewWindow->Hide();
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 );
1126 if ( pItem )
1127 return pItem->mpWindow;
1128 else
1129 return nullptr;
1132 void ToolBox::StartSelection()
1134 if ( mbDrag )
1135 EndSelection();
1137 if ( !mbSelection )
1139 mbSelection = true;
1140 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
1141 mnCurItemId = 0;
1142 Activate();
1146 void ToolBox::EndSelection()
1148 mbCommandDrag = false;
1150 if ( mbDrag || mbSelection )
1152 // reset
1153 mbDrag = false;
1154 mbSelection = false;
1155 if (mnCurPos != TOOLBOX_ITEM_NOTFOUND)
1156 InvalidateItem(mnCurPos);
1157 EndTracking();
1158 if (IsMouseCaptured())
1159 ReleaseMouse();
1160 Deactivate();
1163 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
1164 mnCurItemId = 0;
1165 mnDownItemId = 0;
1166 mnMouseClicks = 0;
1167 mnMouseModifier = 0;
1170 void ToolBox::SetItemDown( sal_uInt16 nItemId, bool bDown )
1172 sal_uInt16 nPos = GetItemPos( nItemId );
1174 if ( nPos != TOOLBOX_ITEM_NOTFOUND )
1176 if ( bDown )
1178 if ( nPos != mnCurPos )
1180 mnCurPos = nPos;
1181 InvalidateItem(mnCurPos);
1182 Flush();
1185 else
1187 if ( nPos == mnCurPos )
1189 InvalidateItem(mnCurPos);
1190 Flush();
1191 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
1195 if ( mbDrag || mbSelection )
1197 mbDrag = false;
1198 mbSelection = false;
1199 EndTracking();
1200 if (IsMouseCaptured())
1201 ReleaseMouse();
1202 Deactivate();
1205 mnCurItemId = 0;
1206 mnDownItemId = 0;
1207 mnMouseClicks = 0;
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();
1231 nGroupPos = nPos;
1232 while ( nGroupPos )
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 );
1240 else
1241 break;
1242 nGroupPos--;
1245 nGroupPos = nPos+1;
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 );
1254 else
1255 break;
1256 nGroupPos++;
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 );
1276 if ( pItem )
1277 return pItem->meState;
1278 else
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];
1289 if ( bEnable )
1290 bEnable = true;
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 );
1299 // update item
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 );
1316 if ( pItem )
1317 return pItem->mbEnabled;
1318 else
1319 return false;
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;
1333 ImplInvalidate();
1338 bool ToolBox::IsItemVisible( sal_uInt16 nItemId ) const
1340 ImplToolItem* pItem = ImplGetItem( nItemId );
1342 if ( pItem )
1343 return pItem->mbVisible;
1344 else
1345 return false;
1348 bool ToolBox::IsItemReallyVisible( sal_uInt16 nItemId ) const
1350 // is the item on the visible area of the toolbox?
1351 bool bRet = false;
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 ) )
1358 bRet = true;
1361 return bRet;
1364 void ToolBox::SetItemCommand(sal_uInt16 nItemId, const OUString& rCommand)
1366 ImplToolItem* pItem = ImplGetItem( nItemId );
1368 if (pItem)
1369 pItem->maCommandStr = rCommand;
1372 const OUString ToolBox::GetItemCommand( sal_uInt16 nItemId ) const
1374 ImplToolItem* pItem = ImplGetItem( nItemId );
1376 if (pItem)
1377 return pItem->maCommandStr;
1379 return OUString();
1382 void ToolBox::SetQuickHelpText( sal_uInt16 nItemId, const OUString& rText )
1384 ImplToolItem* pItem = ImplGetItem( nItemId );
1386 if ( pItem )
1387 pItem->maQuickHelpText = rText;
1390 OUString ToolBox::GetQuickHelpText( sal_uInt16 nItemId ) const
1392 ImplToolItem* pItem = ImplGetItem( nItemId );
1394 if ( pItem )
1395 return pItem->maQuickHelpText;
1396 else
1397 return OUString();
1400 void ToolBox::SetHelpText( sal_uInt16 nItemId, const OUString& rText )
1402 ImplToolItem* pItem = ImplGetItem( nItemId );
1404 if ( pItem )
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 );
1417 if ( pItem )
1418 pItem->maHelpId = rHelpId;
1421 OString ToolBox::GetHelpId( sal_uInt16 nItemId ) const
1423 OString aRet;
1425 ImplToolItem* pItem = ImplGetItem( nItemId );
1427 if ( pItem )
1429 if ( !pItem->maHelpId.isEmpty() )
1430 aRet = pItem->maHelpId;
1431 else
1432 aRet = OUStringToOString( pItem->maCommandStr, RTL_TEXTENCODING_UTF8 );
1435 return aRet;
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) )
1451 mnMaxItemWidth = 1;
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 )
1465 if( it->mbEnabled )
1467 // at least one useful entry
1468 mpData->mbKeyInputDisabled = false;
1469 return;
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];
1509 break;
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
1518 long nIndex = -1;
1519 rItemID = 0;
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];
1531 break;
1535 return nIndex;
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 );
1554 if( pWrapper )
1555 pWrapper->ShowTitleButton( TitleButton::Menu, bool( aType & ToolBoxMenuType::Customize) );
1557 mbFormat = true;
1558 ImplFormat();
1559 ImplSetMinMaxFloatSize( this );
1561 else
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 ?
1593 ImplFormat();
1594 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
1595 while ( it != mpData->m_aItems.end() )
1597 if( it->IsClipped() )
1598 return true;
1599 ++it;
1601 return false;
1604 namespace
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() )
1622 return;
1624 PopupMenu *pMenu = GetMenu();
1626 sal_uInt16 i = 0;
1627 // remove old entries
1628 while( i < pMenu->GetItemCount() )
1630 if( pMenu->GetItemId( i ) >= TOOLBOX_MENUITEM_START )
1632 pMenu->RemoveItem( i );
1633 i = 0;
1635 else
1636 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() )
1726 pWin = pBorderWin;
1727 aMenuRect = pBorderWin->GetMenuRect();
1728 bBorderDel = true;
1732 sal_uInt16 uId = GetMenu()->Execute( pWin, Rectangle( ImplGetPopupPosition( aMenuRect, Size() ), Size() ),
1733 PopupMenuFlags::ExecuteDown | PopupMenuFlags::NoMouseUpClose );
1735 if ( pWin->IsDisposed() )
1736 return;
1738 if( GetMenu() )
1739 GetMenu()->RemoveEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) );
1740 if( bBorderDel )
1742 if( pBorderWin->IsDisposed() )
1743 return;
1746 pWin->Invalidate( aMenuRect );
1748 if( uId )
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
1759 UpdateCustomMenu();
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 )
1771 return false;
1772 else if( mpData->mbAssumeFloating )
1773 return true;
1774 else
1775 return IsFloatingMode();
1778 // checks override first, useful during calculation of sizes
1779 bool ToolBox::ImplIsInPopupMode() const
1781 if( mpData->mbAssumePopupMode )
1782 return true;
1783 else
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 );
1793 if( !pWrapper )
1794 return;
1795 if( mpData->mbIsLocked != bLock )
1797 mpData->mbIsLocked = bLock;
1798 if( !ImplIsFloatingMode() )
1800 mbCalc = true;
1801 mbFormat = true;
1802 SetSizePixel( CalcWindowSizePixel(1) );
1803 Invalidate();
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: */