build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / toolbox.cxx
blob7c5d2a976e0630e589666ccf97e8bb9f4e7a187e
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 <vcl/toolbox.hxx>
21 #include <vcl/commandinfoprovider.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/decoview.hxx>
24 #include <vcl/accel.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/help.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <vcl/mnemonic.hxx>
29 #include <vcl/gradient.hxx>
30 #include <vcl/layout.hxx>
31 #include <vcl/menu.hxx>
32 #include <vcl/settings.hxx>
33 #include <vcl/vclstatuslistener.hxx>
35 #include <tools/debug.hxx>
36 #include <tools/rc.h>
37 #include <tools/poly.hxx>
38 #include <svl/imageitm.hxx>
40 #include <svdata.hxx>
41 #include <window.h>
42 #include <toolbox.h>
43 #include <salframe.hxx>
44 #include <spin.hxx>
45 #if defined(_WIN32)
46 #include <svsys.h>
47 #endif
49 #include <cstdlib>
50 #include <string.h>
51 #include <vector>
52 #include <math.h>
55 #define SMALLBUTTON_HSIZE 7
56 #define SMALLBUTTON_VSIZE 7
58 #define SMALLBUTTON_OFF_NORMAL_X 3
59 #define SMALLBUTTON_OFF_NORMAL_Y 3
61 #define TB_TEXTOFFSET 2
62 #define TB_IMAGETEXTOFFSET 3
63 #define TB_LINESPACING 3
64 #define TB_SPIN_SIZE 14
65 #define TB_SPIN_OFFSET 2
66 #define TB_BORDER_OFFSET1 4
67 #define TB_BORDER_OFFSET2 2
68 #define TB_CUSTOMIZE_OFFSET 2
69 #define TB_RESIZE_OFFSET 3
70 #define TB_MAXLINES 5
71 #define TB_MAXNOSCROLL 32765
73 #define TB_MIN_WIN_WIDTH 20
74 #define TB_DRAGWIDTH 8 // the default width of the drag grip
76 #define TB_CALCMODE_HORZ 1
77 #define TB_CALCMODE_VERT 2
78 #define TB_CALCMODE_FLOAT 3
80 #define TB_WBLINESIZING (WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL)
82 #define DOCK_LINEHSIZE ((sal_uInt16)0x0001)
83 #define DOCK_LINEVSIZE ((sal_uInt16)0x0002)
84 #define DOCK_LINERIGHT ((sal_uInt16)0x1000)
85 #define DOCK_LINEBOTTOM ((sal_uInt16)0x2000)
86 #define DOCK_LINELEFT ((sal_uInt16)0x4000)
87 #define DOCK_LINETOP ((sal_uInt16)0x8000)
88 #define DOCK_LINEOFFSET 3
90 typedef ::std::vector< VclPtr<ToolBox> > ImplTBList;
93 class ImplTBDragMgr
95 private:
96 std::unique_ptr<ImplTBList>
97 mpBoxList;
98 VclPtr<ToolBox> mpDragBox;
99 Point maMouseOff;
100 Rectangle maRect;
101 Rectangle maStartRect;
102 Accelerator maAccel;
103 long mnMinWidth;
104 long mnMaxWidth;
105 sal_uInt16 mnLineMode;
106 sal_uInt16 mnStartLines;
107 void* mpCustomizeData;
108 bool mbResizeMode;
109 bool mbShowDragRect;
111 ImplTBDragMgr(const ImplTBDragMgr&) = delete;
112 ImplTBDragMgr& operator=(const ImplTBDragMgr&) = delete;
114 public:
115 ImplTBDragMgr();
117 void push_back( ToolBox* pBox )
118 { mpBoxList->push_back( pBox ); }
119 void erase( ToolBox* pBox )
121 for ( ImplTBList::iterator it = mpBoxList->begin(); it != mpBoxList->end(); ++it ) {
122 if ( *it == pBox ) {
123 mpBoxList->erase( it );
124 break;
128 size_t size() const
129 { return mpBoxList->size(); }
131 ToolBox* FindToolBox( const Rectangle& rRect );
133 void StartDragging( ToolBox* pDragBox, const Point& rPos, const Rectangle& rRect, sal_uInt16 nLineMode,
134 bool bResizeItem );
135 void Dragging( const Point& rPos );
136 void EndDragging( bool bOK = true );
137 void HideDragRect() { if ( mbShowDragRect ) mpDragBox->HideTracking(); }
138 void UpdateDragRect();
139 DECL_LINK( SelectHdl, Accelerator&, void );
143 static ImplTBDragMgr* ImplGetTBDragMgr()
145 ImplSVData* pSVData = ImplGetSVData();
146 if ( !pSVData->maCtrlData.mpTBDragMgr )
147 pSVData->maCtrlData.mpTBDragMgr = new ImplTBDragMgr;
148 return pSVData->maCtrlData.mpTBDragMgr;
151 int ToolBox::ImplGetDragWidth( ToolBox* pThis )
153 int nWidth = TB_DRAGWIDTH;
154 if( pThis->IsNativeControlSupported( ControlType::Toolbar, ControlPart::Entire ) )
157 ImplControlValue aControlValue;
158 Point aPoint;
159 Rectangle aContent, aBound;
160 Rectangle aArea( aPoint, pThis->GetOutputSizePixel() );
162 if ( pThis->GetNativeControlRegion(ControlType::Toolbar, pThis->mbHorz ? ControlPart::ThumbVert : ControlPart::ThumbHorz,
163 aArea, ControlState::NONE, aControlValue, OUString(), aBound, aContent) )
165 nWidth = pThis->mbHorz ? aContent.GetWidth() : aContent.GetHeight();
169 // increase the hit area of the drag handle according to DPI scale factor
170 nWidth *= pThis->GetDPIScaleFactor();
172 return nWidth;
175 ButtonType determineButtonType( ImplToolItem* pItem, ButtonType defaultType )
177 ButtonType tmpButtonType = defaultType;
178 if ( pItem->mnBits & (ToolBoxItemBits::TEXT_ONLY | ToolBoxItemBits::ICON_ONLY) ) // item has custom setting
180 tmpButtonType = ButtonType::SYMBOLTEXT;
181 if ( pItem->mnBits & ToolBoxItemBits::TEXT_ONLY )
182 tmpButtonType = ButtonType::TEXT;
183 else if ( pItem->mnBits & ToolBoxItemBits::ICON_ONLY )
184 tmpButtonType = ButtonType::SYMBOLONLY;
186 return tmpButtonType;
189 void ToolBox::ImplUpdateDragArea( ToolBox *pThis )
191 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
192 if( pWrapper )
194 if ( pThis->ImplIsFloatingMode() || pWrapper->IsLocked() )
195 pWrapper->SetDragArea( Rectangle() );
196 else
198 if( pThis->meAlign == WindowAlign::Top || pThis->meAlign == WindowAlign::Bottom )
199 pWrapper->SetDragArea( Rectangle( 0, 0, ImplGetDragWidth( pThis ), pThis->GetOutputSizePixel().Height() ) );
200 else
201 pWrapper->SetDragArea( Rectangle( 0, 0, pThis->GetOutputSizePixel().Width(), ImplGetDragWidth( pThis ) ) );
206 void ToolBox::ImplCalcBorder( WindowAlign eAlign, long& rLeft, long& rTop,
207 long& rRight, long& rBottom, const ToolBox *pThis )
209 if( pThis->ImplIsFloatingMode() || !(pThis->mnWinStyle & WB_BORDER) )
211 // no border in floating mode
212 rLeft = rTop = rRight = rBottom = 0;
213 return;
216 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
218 // reserve DragArea only for dockable toolbars
219 int dragwidth = ( pWrapper && !pWrapper->IsLocked() ) ? ImplGetDragWidth( const_cast<ToolBox*>(pThis) ) : 0;
221 // no shadow border for dockable toolbars
222 int borderwidth = pWrapper ? 0: 2;
224 if ( eAlign == WindowAlign::Top )
226 rLeft = borderwidth+dragwidth;
227 rTop = borderwidth;
228 rRight = borderwidth;
229 rBottom = 0;
231 else if ( eAlign == WindowAlign::Left )
233 rLeft = borderwidth;
234 rTop = borderwidth+dragwidth;
235 rRight = 0;
236 rBottom = borderwidth;
238 else if ( eAlign == WindowAlign::Bottom )
240 rLeft = borderwidth+dragwidth;
241 rTop = 0;
242 rRight = borderwidth;
243 rBottom = borderwidth;
245 else
247 rLeft = 0;
248 rTop = borderwidth+dragwidth;
249 rRight = borderwidth;
250 rBottom = borderwidth;
254 static void ImplCheckUpdate(ToolBox* pThis)
256 // remove any pending invalidates to avoid
257 // have them triggered when paint is locked (see mpData->mbIsPaintLocked)
258 // which would result in erasing the background only and not painting any items
259 // this must not be done when we're already in Paint()
261 // this is only required for transparent toolbars (see ImplDrawTransparentBackground() )
262 if( !pThis->IsBackground() && pThis->HasPaintEvent() && !pThis->IsInPaint() )
263 pThis->Update();
266 void ToolBox::ImplDrawGrip(vcl::RenderContext& rRenderContext)
268 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
269 if( pWrapper && !pWrapper->GetDragArea().IsEmpty() )
271 // execute pending paint requests
272 ImplCheckUpdate(this);
274 bool bNativeOk = false;
275 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, mbHorz ? ControlPart::ThumbHorz : ControlPart::ThumbVert))
277 ToolbarValue aToolbarValue;
278 aToolbarValue.maGripRect = pWrapper->GetDragArea();
280 Point aPt;
281 Rectangle aCtrlRegion(aPt, GetOutputSizePixel());
282 ControlState nState = ControlState::ENABLED;
284 bNativeOk = rRenderContext.DrawNativeControl( ControlType::Toolbar, mbHorz ? ControlPart::ThumbVert : ControlPart::ThumbHorz,
285 aCtrlRegion, nState, aToolbarValue, OUString() );
288 if( bNativeOk )
289 return;
291 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
292 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
293 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
295 Size aSz(GetOutputSizePixel());
296 float fScaleFactor = rRenderContext.GetDPIScaleFactor();
298 if (meAlign == WindowAlign::Top || meAlign == WindowAlign::Bottom)
300 int height = (int) (0.6 * aSz.Height() + 0.5);
301 int i = (aSz.Height() - height) / 2;
302 height += i;
303 while (i <= height)
305 int x = ImplGetDragWidth(this) / 2;
306 rRenderContext.DrawEllipse(Rectangle(Point(x, i), Size(2 * fScaleFactor, 2 * fScaleFactor)));
307 i += 4 * fScaleFactor;
310 else
312 int width = (int) (0.6 * aSz.Width() + 0.5);
313 int i = (aSz.Width() - width) / 2;
314 width += i;
315 while (i <= width)
317 int y = ImplGetDragWidth(this) / 2;
318 rRenderContext.DrawEllipse(Rectangle(Point(i, y), Size(2 * fScaleFactor, 2 * fScaleFactor)));
319 i += 4 * fScaleFactor;
325 void ToolBox::ImplDrawGradientBackground(vcl::RenderContext& rRenderContext, ImplDockingWindowWrapper*)
327 // draw a nice gradient
329 Color startCol, endCol;
330 const StyleSettings rSettings = rRenderContext.GetSettings().GetStyleSettings();
332 startCol = rSettings.GetFaceGradientColor();
333 endCol = rSettings.GetFaceColor();
334 if (rSettings.GetHighContrastMode())
335 // no 'extreme' gradient when high contrast
336 startCol = endCol;
338 Gradient g;
339 g.SetAngle(mbHorz ? 0 : 900);
340 g.SetStyle(GradientStyle::Linear);
342 g.SetStartColor(startCol);
343 g.SetEndColor(endCol);
345 bool bLineColor = rRenderContext.IsLineColor();
346 Color aOldCol = rRenderContext.GetLineColor();
347 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
349 Size aFullSz(GetOutputSizePixel());
350 Size aLineSz(aFullSz);
352 // use the linesize only when floating
353 // full window height is used when docked (single line)
354 if (ImplIsFloatingMode())
356 long nLineSize;
357 if (mbHorz)
359 nLineSize = mnMaxItemHeight;
360 if (mnWinHeight > mnMaxItemHeight)
361 nLineSize = mnWinHeight;
363 aLineSz.Height() = nLineSize;
365 else
367 nLineSize = mnMaxItemWidth;
368 aLineSz.Width() = nLineSize;
372 long nLeft, nTop, nRight, nBottom;
373 ImplCalcBorder(meAlign, nLeft, nTop, nRight, nBottom, this);
375 Size aTopLineSz(aLineSz);
376 Size aBottomLineSz(aLineSz);
378 if (mnWinStyle & WB_BORDER)
380 if (mbHorz)
382 aTopLineSz.Height() += TB_BORDER_OFFSET2 + nTop;
383 aBottomLineSz.Height() += TB_BORDER_OFFSET2 + nBottom;
385 if (mnCurLines == 1)
386 aTopLineSz.Height() += TB_BORDER_OFFSET2 + nBottom;
388 else
390 aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft;
391 aBottomLineSz.Width() += TB_BORDER_OFFSET1 + nRight;
393 if (mnCurLines == 1)
394 aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft;
398 if (mnWinStyle & WB_LINESPACING)
400 if (mbHorz)
402 aLineSz.Height() += TB_LINESPACING;
403 if (mnCurLines > 1)
404 aTopLineSz.Height() += TB_LINESPACING;
406 else
408 aLineSz.Width() += TB_LINESPACING;
409 if (mnCurLines > 1)
410 aTopLineSz.Width() += TB_LINESPACING;
414 if (mbHorz)
416 long y = 0;
418 rRenderContext.DrawGradient(Rectangle(0, y, aTopLineSz.Width(), y + aTopLineSz.Height()), g);
419 y += aTopLineSz.Height();
421 while (y < (mnDY - aBottomLineSz.Height()))
423 rRenderContext.DrawGradient(Rectangle(0, y, aLineSz.Width(), y + aLineSz.Height()), g);
424 y += aLineSz.Height();
427 rRenderContext.DrawGradient(Rectangle(0, y, aBottomLineSz.Width(), y + aBottomLineSz.Height()), g);
429 else
431 long x = 0;
433 rRenderContext.DrawGradient(Rectangle(x, 0, x + aTopLineSz.Width(), aTopLineSz.Height()), g);
434 x += aTopLineSz.Width();
436 while (x < (mnDX - aBottomLineSz.Width()))
438 rRenderContext.DrawGradient(Rectangle(x, 0, x + aLineSz.Width(), aLineSz.Height()), g);
439 x += aLineSz.Width();
442 rRenderContext.DrawGradient(Rectangle( x, 0, x + aBottomLineSz.Width(), aBottomLineSz.Height()), g);
445 if( bLineColor )
446 rRenderContext.SetLineColor( aOldCol );
450 bool ToolBox::ImplDrawNativeBackground(vcl::RenderContext& rRenderContext, const vcl::Region& /*rRegion*/)
452 // use NWF
453 Point aPt;
454 Rectangle aCtrlRegion(aPt, GetOutputSizePixel());
455 ControlState nState = ControlState::ENABLED;
457 return rRenderContext.DrawNativeControl( ControlType::Toolbar, mbHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert,
458 aCtrlRegion, nState, ImplControlValue(), OUString() );
461 void ToolBox::ImplDrawTransparentBackground(vcl::RenderContext& /*rRenderContext*/, const vcl::Region &rRegion)
463 // just invalidate to trigger paint of the parent
464 const bool bOldPaintLock = mpData->mbIsPaintLocked;
465 mpData->mbIsPaintLocked = true;
467 // send an invalidate to the first opaque parent and invalidate the whole hierarchy from there (noclipchildren)
468 Invalidate(rRegion, InvalidateFlags::Update | InvalidateFlags::NoClipChildren);
470 mpData->mbIsPaintLocked = bOldPaintLock;
473 void ToolBox::ImplDrawConstantBackground(vcl::RenderContext& rRenderContext, const vcl::Region &rRegion, bool bIsInPopupMode)
475 // draw a constant color
476 if (!bIsInPopupMode)
478 // default background
479 rRenderContext.Erase(rRegion.GetBoundRect());
481 else
483 // use different color in popupmode
484 const StyleSettings rSettings = rRenderContext.GetSettings().GetStyleSettings();
485 Wallpaper aWallpaper(rSettings.GetFaceGradientColor());
486 rRenderContext.DrawWallpaper(rRegion.GetBoundRect(), aWallpaper);
490 void ToolBox::ImplDrawBackground(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
492 // execute pending paint requests
493 ImplCheckUpdate(this);
495 ImplDockingWindowWrapper* pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
496 bool bIsInPopupMode = ImplIsInPopupMode();
498 vcl::Region aPaintRegion(rRect);
500 // make sure we do not invalidate/erase too much
501 if (IsInPaint())
502 aPaintRegion.Intersect(GetActiveClipRegion());
504 rRenderContext.Push(PushFlags::CLIPREGION);
505 rRenderContext.IntersectClipRegion( aPaintRegion );
507 if (!pWrapper)
509 // no gradient for ordinary toolbars (not dockable)
510 if( !IsBackground() && !IsInPaint() )
511 ImplDrawTransparentBackground(rRenderContext, aPaintRegion);
512 else
513 ImplDrawConstantBackground(rRenderContext, aPaintRegion, bIsInPopupMode);
515 else
517 // toolbars known to the dockingmanager will be drawn using NWF or a gradient
518 // docked toolbars are transparent and NWF is already used in the docking area which is their common background
519 // so NWF is used here for floating toolbars only
520 bool bNativeOk = false;
521 if( ImplIsFloatingMode() && rRenderContext.IsNativeControlSupported( ControlType::Toolbar, ControlPart::Entire) )
522 bNativeOk = ImplDrawNativeBackground(rRenderContext, aPaintRegion);
523 const StyleSettings rSetting = Application::GetSettings().GetStyleSettings();
524 if (!bNativeOk)
526 const bool isFooter = GetAlign() == WindowAlign::Bottom && !rSetting.GetPersonaFooter().IsEmpty();
527 if (!IsBackground() ||
528 ((GetAlign() == WindowAlign::Top && !rSetting.GetPersonaHeader().IsEmpty() ) || isFooter))
530 if (!IsInPaint())
531 ImplDrawTransparentBackground(rRenderContext, aPaintRegion);
533 else
534 ImplDrawGradientBackground(rRenderContext, pWrapper);
538 // restore clip region
539 rRenderContext.Pop();
542 void ToolBox::ImplErase(vcl::RenderContext& rRenderContext, const Rectangle &rRect, bool bHighlight, bool bHasOpenPopup)
544 // the background of non NWF buttons is painted in a constant color
545 // to have the same highlight color (transparency in DrawSelectionBackground())
546 // items with open popups will also painted using a constant color
547 if (!mpData->mbNativeButtons &&
548 (bHighlight || !(GetStyle() & WB_3DLOOK)))
550 if (GetStyle() & WB_3DLOOK)
552 rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
553 rRenderContext.SetLineColor();
554 if (bHasOpenPopup)
555 // choose the same color as the popup will use
556 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceGradientColor());
557 else
558 rRenderContext.SetFillColor(Color(COL_WHITE));
560 rRenderContext.DrawRect(rRect);
561 rRenderContext.Pop();
563 else
564 ImplDrawBackground(rRenderContext, rRect);
566 else
567 ImplDrawBackground(rRenderContext, rRect);
570 void ToolBox::ImplDrawBorder(vcl::RenderContext& rRenderContext)
572 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
573 long nDX = mnDX;
574 long nDY = mnDY;
576 ImplDockingWindowWrapper* pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
578 // draw borders for ordinary toolbars only (not dockable)
579 if( pWrapper )
580 return;
582 if (meAlign == WindowAlign::Bottom)
584 // draw bottom border
585 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
586 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
587 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
588 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
590 else
592 // draw top border
593 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
594 rRenderContext.DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
595 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
596 rRenderContext.DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) );
598 if (meAlign == WindowAlign::Left || meAlign == WindowAlign::Right)
600 if (meAlign == WindowAlign::Left)
602 // draw left-bottom border
603 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
604 rRenderContext.DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
605 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
606 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
607 rRenderContext.DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
608 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
610 else
612 // draw right-bottom border
613 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
614 rRenderContext.DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
615 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) );
616 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
617 rRenderContext.DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
618 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
623 if ( meAlign == WindowAlign::Bottom || meAlign == WindowAlign::Top )
625 // draw right border
626 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
627 rRenderContext.DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) );
628 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
629 rRenderContext.DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
633 static bool ImplIsFixedControl( const ImplToolItem *pItem )
635 return ( pItem->mpWindow &&
636 (pItem->mpWindow->GetType() == WINDOW_FIXEDTEXT ||
637 pItem->mpWindow->GetType() == WINDOW_FIXEDLINE ||
638 pItem->mpWindow->GetType() == WINDOW_GROUPBOX) );
641 const ImplToolItem *ToolBox::ImplGetFirstClippedItem( const ToolBox* pThis )
643 std::vector< ImplToolItem >::const_iterator it;
644 it = pThis->mpData->m_aItems.begin();
645 while ( it != pThis->mpData->m_aItems.end() )
647 if( it->IsClipped() )
648 return &(*it);
649 ++it;
651 return nullptr;
654 Size ToolBox::ImplCalcSize( const ToolBox* pThis, sal_uInt16 nCalcLines, sal_uInt16 nCalcMode )
656 long nMax;
657 long nLeft = 0;
658 long nTop = 0;
659 long nRight = 0;
660 long nBottom = 0;
661 Size aSize;
662 WindowAlign eOldAlign = pThis->meAlign;
663 bool bOldHorz = pThis->mbHorz;
664 bool bOldAssumeDocked = pThis->mpData->mbAssumeDocked;
665 bool bOldAssumeFloating = pThis->mpData->mbAssumeFloating;
667 if ( nCalcMode )
669 bool bOldFloatingMode = pThis->ImplIsFloatingMode();
671 pThis->mpData->mbAssumeDocked = false;
672 pThis->mpData->mbAssumeFloating = false;
674 if ( nCalcMode == TB_CALCMODE_HORZ )
676 pThis->mpData->mbAssumeDocked = true; // force non-floating mode during calculation
677 ImplCalcBorder( WindowAlign::Top, nLeft, nTop, nRight, nBottom, pThis );
678 const_cast<ToolBox*>(pThis)->mbHorz = true;
679 if ( pThis->mbHorz != bOldHorz )
680 const_cast<ToolBox*>(pThis)->meAlign = WindowAlign::Top;
682 else if ( nCalcMode == TB_CALCMODE_VERT )
684 pThis->mpData->mbAssumeDocked = true; // force non-floating mode during calculation
685 ImplCalcBorder( WindowAlign::Left, nLeft, nTop, nRight, nBottom, pThis );
686 const_cast<ToolBox*>(pThis)->mbHorz = false;
687 if ( pThis->mbHorz != bOldHorz )
688 const_cast<ToolBox*>(pThis)->meAlign = WindowAlign::Left;
690 else if ( nCalcMode == TB_CALCMODE_FLOAT )
692 pThis->mpData->mbAssumeFloating = true; // force non-floating mode during calculation
693 nLeft = nTop = nRight = nBottom = 0;
694 const_cast<ToolBox*>(pThis)->mbHorz = true;
695 if ( pThis->mbHorz != bOldHorz )
696 const_cast<ToolBox*>(pThis)->meAlign = WindowAlign::Top;
699 if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) ||
700 (pThis->ImplIsFloatingMode() != bOldFloatingMode ) )
701 const_cast<ToolBox*>(pThis)->mbCalc = true;
703 else
704 ImplCalcBorder( pThis->meAlign, nLeft, nTop, nRight, nBottom, pThis );
706 const_cast<ToolBox*>(pThis)->ImplCalcItem();
708 if( !nCalcMode && pThis->ImplIsFloatingMode() )
710 aSize = ImplCalcFloatSize( const_cast<ToolBox*>(pThis), nCalcLines );
712 else
714 if ( pThis->mbHorz )
716 if ( pThis->mnWinHeight > pThis->mnMaxItemHeight )
717 aSize.Height() = nCalcLines * pThis->mnWinHeight;
718 else
719 aSize.Height() = nCalcLines * pThis->mnMaxItemHeight;
721 if ( pThis->mnWinStyle & WB_LINESPACING )
722 aSize.Height() += (nCalcLines-1)*TB_LINESPACING;
724 if ( pThis->mnWinStyle & WB_BORDER )
725 aSize.Height() += (TB_BORDER_OFFSET2*2) + nTop + nBottom;
727 nMax = 0;
728 const_cast<ToolBox*>(pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz );
729 if ( nMax )
730 aSize.Width() += nMax;
732 if ( pThis->mnWinStyle & WB_BORDER )
733 aSize.Width() += (TB_BORDER_OFFSET1*2) + nLeft + nRight;
735 else
737 aSize.Width() = nCalcLines * pThis->mnMaxItemWidth;
739 if ( pThis->mnWinStyle & WB_LINESPACING )
740 aSize.Width() += (nCalcLines-1)*TB_LINESPACING;
742 if ( pThis->mnWinStyle & WB_BORDER )
743 aSize.Width() += (TB_BORDER_OFFSET2*2) + nLeft + nRight;
745 nMax = 0;
746 const_cast<ToolBox*>(pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz );
747 if ( nMax )
748 aSize.Height() += nMax;
750 if ( pThis->mnWinStyle & WB_BORDER )
751 aSize.Height() += (TB_BORDER_OFFSET1*2) + nTop + nBottom;
754 // restore previous values
755 if ( nCalcMode )
757 pThis->mpData->mbAssumeDocked = bOldAssumeDocked;
758 pThis->mpData->mbAssumeFloating = bOldAssumeFloating;
759 if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) )
761 const_cast<ToolBox*>(pThis)->meAlign = eOldAlign;
762 const_cast<ToolBox*>(pThis)->mbHorz = bOldHorz;
763 const_cast<ToolBox*>(pThis)->mbCalc = true;
767 return aSize;
770 void ToolBox::ImplCalcFloatSizes( ToolBox* pThis )
772 if ( !pThis->maFloatSizes.empty() )
773 return;
775 // calculate the minimal size, i.e. where the biggest item just fits
776 long nCalcSize = 0;
778 std::vector< ImplToolItem >::const_iterator it;
779 it = pThis->mpData->m_aItems.begin();
780 while ( it != pThis->mpData->m_aItems.end() )
782 if ( it->mbVisible )
784 if ( it->mpWindow )
786 long nTempSize = it->mpWindow->GetSizePixel().Width();
787 if ( nTempSize > nCalcSize )
788 nCalcSize = nTempSize;
790 else
792 if( it->maItemSize.Width() > nCalcSize )
793 nCalcSize = it->maItemSize.Width();
796 ++it;
799 // calc an upper bound for ImplCalcBreaks below
800 long upperBoundWidth = nCalcSize * pThis->mpData->m_aItems.size();
802 sal_uInt16 nLines;
803 sal_uInt16 nCalcLines;
804 sal_uInt16 nTempLines;
805 long nMaxLineWidth;
806 nCalcLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, true );
808 pThis->maFloatSizes.reserve( nCalcLines );
810 nTempLines = nLines = nCalcLines;
811 while ( nLines )
813 long nHeight = ImplCalcSize( pThis, nTempLines, TB_CALCMODE_FLOAT ).Height();
815 ImplToolSize aSize;
816 aSize.mnWidth = nMaxLineWidth+(TB_BORDER_OFFSET1*2);
817 aSize.mnHeight = nHeight;
818 aSize.mnLines = nTempLines;
819 pThis->maFloatSizes.push_back( aSize );
820 nLines--;
821 if ( nLines )
825 nCalcSize += pThis->mnMaxItemWidth;
826 nTempLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, true );
828 while ( (nCalcSize < upperBoundWidth) && (nLines < nTempLines) && (nTempLines != 1) );
829 if ( nTempLines < nLines )
830 nLines = nTempLines;
835 Size ToolBox::ImplCalcFloatSize( ToolBox* pThis, sal_uInt16& rLines )
837 ImplCalcFloatSizes( pThis );
839 if ( !rLines )
841 rLines = pThis->mnFloatLines;
842 if ( !rLines )
843 rLines = pThis->mnLines;
846 sal_uInt16 i = 0;
847 while ( i + 1u < pThis->maFloatSizes.size() && rLines < pThis->maFloatSizes[i].mnLines )
849 i++;
852 Size aSize( pThis->maFloatSizes[i].mnWidth, pThis->maFloatSizes[i].mnHeight );
853 rLines = pThis->maFloatSizes[i].mnLines;
855 return aSize;
858 void ToolBox::ImplCalcMinMaxFloatSize( ToolBox* pThis, Size& rMinSize, Size& rMaxSize )
860 ImplCalcFloatSizes( pThis );
862 sal_uInt16 i = 0;
863 rMinSize = Size( pThis->maFloatSizes[i].mnWidth, pThis->maFloatSizes[i].mnHeight );
864 rMaxSize = Size( pThis->maFloatSizes[i].mnWidth, pThis->maFloatSizes[i].mnHeight );
865 while ( ++i < pThis->maFloatSizes.size() )
867 if( pThis->maFloatSizes[i].mnWidth < rMinSize.Width() )
868 rMinSize.Width() = pThis->maFloatSizes[i].mnWidth;
869 if( pThis->maFloatSizes[i].mnHeight < rMinSize.Height() )
870 rMinSize.Height() = pThis->maFloatSizes[i].mnHeight;
872 if( pThis->maFloatSizes[i].mnWidth > rMaxSize.Width() )
873 rMaxSize.Width() = pThis->maFloatSizes[i].mnWidth;
874 if( pThis->maFloatSizes[i].mnHeight > rMaxSize.Height() )
875 rMaxSize.Height() = pThis->maFloatSizes[i].mnHeight;
879 void ToolBox::ImplSetMinMaxFloatSize( ToolBox *pThis )
881 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis );
882 Size aMinSize, aMaxSize;
883 ImplCalcMinMaxFloatSize( pThis, aMinSize, aMaxSize );
884 if( pWrapper )
886 pWrapper->SetMinOutputSizePixel( aMinSize );
887 pWrapper->SetMaxOutputSizePixel( aMaxSize );
888 pWrapper->ShowTitleButton( TitleButton::Menu, bool( pThis->GetMenuType() & ToolBoxMenuType::Customize) );
890 else
892 // TODO: change SetMinOutputSizePixel to be not inline
893 pThis->SetMinOutputSizePixel( aMinSize );
894 pThis->SetMaxOutputSizePixel( aMaxSize );
898 sal_uInt16 ToolBox::ImplCalcLines( ToolBox* pThis, long nToolSize )
900 long nLineHeight;
902 if ( pThis->mbHorz )
904 if ( pThis->mnWinHeight > pThis->mnMaxItemHeight )
905 nLineHeight = pThis->mnWinHeight;
906 else
907 nLineHeight = pThis->mnMaxItemHeight;
909 else
910 nLineHeight = pThis->mnMaxItemWidth;
912 if ( pThis->mnWinStyle & WB_BORDER )
913 nToolSize -= TB_BORDER_OFFSET2*2;
915 if ( pThis->mnWinStyle & WB_LINESPACING )
917 nLineHeight += TB_LINESPACING;
918 nToolSize += TB_LINESPACING;
921 // #i91917# always report at least one line
922 long nLines = nToolSize/nLineHeight;
923 if( nLines < 1 )
924 nLines = 1;
926 return static_cast<sal_uInt16>(nLines);
929 sal_uInt16 ToolBox::ImplTestLineSize( ToolBox* pThis, const Point& rPos )
931 if ( !pThis->ImplIsFloatingMode() &&
932 (!pThis->mbScroll || (pThis->mnLines > 1) || (pThis->mnCurLines > pThis->mnVisLines)) )
934 WindowAlign eAlign = pThis->GetAlign();
936 if ( eAlign == WindowAlign::Left )
938 if ( rPos.X() > pThis->mnDX-DOCK_LINEOFFSET )
939 return DOCK_LINEHSIZE | DOCK_LINERIGHT;
941 else if ( eAlign == WindowAlign::Top )
943 if ( rPos.Y() > pThis->mnDY-DOCK_LINEOFFSET )
944 return DOCK_LINEVSIZE | DOCK_LINEBOTTOM;
946 else if ( eAlign == WindowAlign::Right )
948 if ( rPos.X() < DOCK_LINEOFFSET )
949 return DOCK_LINEHSIZE | DOCK_LINELEFT;
951 else if ( eAlign == WindowAlign::Bottom )
953 if ( rPos.Y() < DOCK_LINEOFFSET )
954 return DOCK_LINEVSIZE | DOCK_LINETOP;
958 return 0;
961 void ToolBox::ImplLineSizing( ToolBox* pThis, const Point& rPos, Rectangle& rRect, sal_uInt16 nLineMode )
963 bool bHorz;
964 long nOneLineSize;
965 long nCurSize;
966 long nMaxSize;
967 long nSize;
968 Size aSize;
970 if ( nLineMode & DOCK_LINERIGHT )
972 nCurSize = rPos.X() - rRect.Left();
973 bHorz = false;
975 else if ( nLineMode & DOCK_LINEBOTTOM )
977 nCurSize = rPos.Y() - rRect.Top();
978 bHorz = true;
980 else if ( nLineMode & DOCK_LINELEFT )
982 nCurSize = rRect.Right() - rPos.X();
983 bHorz = false;
985 else if ( nLineMode & DOCK_LINETOP )
987 nCurSize = rRect.Bottom() - rPos.Y();
988 bHorz = true;
990 else {
991 OSL_FAIL( "ImplLineSizing: Trailing else" );
992 nCurSize = 0;
993 bHorz = false;
996 Size aWinSize = pThis->GetSizePixel();
997 sal_uInt16 nMaxLines = (pThis->mnLines > pThis->mnCurLines) ? pThis->mnLines : pThis->mnCurLines;
998 if ( nMaxLines > TB_MAXLINES )
999 nMaxLines = TB_MAXLINES;
1000 if ( bHorz )
1002 nOneLineSize = ImplCalcSize( pThis, 1 ).Height();
1003 nMaxSize = pThis->maOutDockRect.GetHeight() - 20;
1004 if ( nMaxSize < aWinSize.Height() )
1005 nMaxSize = aWinSize.Height();
1007 else
1009 nOneLineSize = ImplCalcSize( pThis, 1 ).Width();
1010 nMaxSize = pThis->maOutDockRect.GetWidth() - 20;
1011 if ( nMaxSize < aWinSize.Width() )
1012 nMaxSize = aWinSize.Width();
1015 sal_uInt16 i = 1;
1016 if ( nCurSize <= nOneLineSize )
1017 nSize = nOneLineSize;
1018 else
1020 nSize = 0;
1021 while ( (nSize < nCurSize) && (i < nMaxLines) )
1023 i++;
1024 aSize = ImplCalcSize( pThis, i );
1025 if ( bHorz )
1026 nSize = aSize.Height();
1027 else
1028 nSize = aSize.Width();
1029 if ( nSize > nMaxSize )
1031 i--;
1032 aSize = ImplCalcSize( pThis, i );
1033 if ( bHorz )
1034 nSize = aSize.Height();
1035 else
1036 nSize = aSize.Width();
1037 break;
1042 if ( nLineMode & DOCK_LINERIGHT )
1043 rRect.Right() = rRect.Left()+nSize-1;
1044 else if ( nLineMode & DOCK_LINEBOTTOM )
1045 rRect.Bottom() = rRect.Top()+nSize-1;
1046 else if ( nLineMode & DOCK_LINELEFT )
1047 rRect.Left() = rRect.Right()-nSize;
1048 else
1049 rRect.Top() = rRect.Bottom()-nSize;
1051 pThis->mnDockLines = i;
1054 sal_uInt16 ToolBox::ImplFindItemPos( ToolBox* pBox, const Point& rPos )
1056 sal_uInt16 nPos = 0;
1057 long nLast = 0;
1058 Point aPos = rPos;
1059 Size aSize( pBox->mnDX, pBox->mnDY );
1061 if ( aPos.X() > aSize.Width()-TB_BORDER_OFFSET1 )
1062 aPos.X() = aSize.Width()-TB_BORDER_OFFSET1;
1063 if ( aPos.Y() > aSize.Height()-TB_BORDER_OFFSET1 )
1064 aPos.Y() = aSize.Height()-TB_BORDER_OFFSET1;
1066 // Item suchen, das geklickt wurde
1067 std::vector< ImplToolItem >::const_iterator it = pBox->mpData->m_aItems.begin();
1068 while ( it != pBox->mpData->m_aItems.end() )
1070 if ( it->mbVisible )
1072 if ( nLast || !it->maRect.IsEmpty() )
1074 if ( pBox->mbHorz )
1076 if ( nLast &&
1077 ((nLast < it->maRect.Top()) || it->maRect.IsEmpty()) )
1078 return nPos;
1080 if ( aPos.Y() <= it->maRect.Bottom() )
1082 if ( aPos.X() < it->maRect.Left() )
1083 return nPos;
1084 else if ( aPos.X() < it->maRect.Right() )
1085 return nPos+1;
1086 else if ( !nLast )
1087 nLast = it->maRect.Bottom();
1090 else
1092 if ( nLast &&
1093 ((nLast < it->maRect.Left()) || it->maRect.IsEmpty()) )
1094 return nPos;
1096 if ( aPos.X() <= it->maRect.Right() )
1098 if ( aPos.Y() < it->maRect.Top() )
1099 return nPos;
1100 else if ( aPos.Y() < it->maRect.Bottom() )
1101 return nPos+1;
1102 else if ( !nLast )
1103 nLast = it->maRect.Right();
1109 nPos++;
1110 ++it;
1113 return nPos;
1116 ImplTBDragMgr::ImplTBDragMgr()
1117 : mpBoxList(new ImplTBList())
1118 , mpDragBox(nullptr)
1119 , mnMinWidth(0)
1120 , mnMaxWidth(0)
1121 , mnLineMode(0)
1122 , mnStartLines(0)
1123 , mpCustomizeData(nullptr)
1124 , mbResizeMode(false)
1125 , mbShowDragRect(false)
1127 maAccel.InsertItem( KEY_RETURN, vcl::KeyCode( KEY_RETURN ) );
1128 maAccel.InsertItem( KEY_ESCAPE, vcl::KeyCode( KEY_ESCAPE ) );
1129 maAccel.SetSelectHdl( LINK( this, ImplTBDragMgr, SelectHdl ) );
1132 ToolBox* ImplTBDragMgr::FindToolBox( const Rectangle& rRect )
1134 for (VclPtr<ToolBox> & i : *mpBoxList)
1136 ToolBox* pBox = i;
1138 * FIXME: since we can have multiple frames now we cannot
1139 * find the drag target by its position alone.
1140 * As long as the toolbar config dialogue is not a system window
1141 * this works in one frame only anyway. If the dialogue
1142 * changes to a system window, we need a new implementation here
1144 if ( pBox->IsReallyVisible()
1145 && pBox->ImplGetWindowImpl()->mpFrame == mpDragBox->ImplGetWindowImpl()->mpFrame
1147 if ( !pBox->ImplIsFloatingMode() )
1149 Point aPos = pBox->GetPosPixel();
1150 aPos = pBox->GetParent()->OutputToScreenPixel( aPos );
1151 Rectangle aTempRect( aPos, pBox->GetSizePixel() );
1152 if ( aTempRect.IsOver( rRect ) )
1153 return pBox;
1158 return nullptr;
1161 void ImplTBDragMgr::StartDragging( ToolBox* pToolBox,
1162 const Point& rPos, const Rectangle& rRect,
1163 sal_uInt16 nDragLineMode, bool bResizeItem )
1165 mpDragBox = pToolBox;
1166 pToolBox->CaptureMouse();
1167 pToolBox->mbDragging = true;
1168 Application::InsertAccel( &maAccel );
1170 if ( nDragLineMode )
1172 mnLineMode = nDragLineMode;
1173 mnStartLines = pToolBox->mnDockLines;
1175 else
1177 mpCustomizeData = nullptr;
1178 mbResizeMode = bResizeItem;
1179 pToolBox->Activate();
1180 pToolBox->mnCurItemId = pToolBox->mnConfigItem;
1181 pToolBox->Highlight();
1182 pToolBox->mnCurItemId = 0;
1183 if ( mbResizeMode )
1185 if ( rRect.GetWidth() < TB_MIN_WIN_WIDTH )
1186 mnMinWidth = rRect.GetWidth();
1187 else
1188 mnMinWidth = TB_MIN_WIN_WIDTH;
1189 mnMaxWidth = pToolBox->GetSizePixel().Width()-rRect.Left()-
1190 TB_SPIN_SIZE-TB_BORDER_OFFSET1-(TB_SPIN_OFFSET*2);
1194 // MouseOffset berechnen
1195 maMouseOff.X() = rRect.Left() - rPos.X();
1196 maMouseOff.Y() = rRect.Top() - rPos.Y();
1197 maRect = rRect;
1198 maStartRect = rRect;
1199 mbShowDragRect = true;
1200 pToolBox->ShowTracking( maRect );
1203 void ImplTBDragMgr::Dragging( const Point& rPos )
1205 if ( mnLineMode )
1207 ToolBox::ImplLineSizing( mpDragBox, rPos, maRect, mnLineMode );
1208 Point aOff = mpDragBox->OutputToScreenPixel( Point() );
1209 maRect.Move( aOff.X(), aOff.Y() );
1210 mpDragBox->Docking( rPos, maRect );
1211 maRect.Move( -aOff.X(), -aOff.Y() );
1212 mpDragBox->ShowTracking( maRect );
1214 else
1216 if ( mbResizeMode )
1218 long nXOff = rPos.X()-maStartRect.Left();
1219 nXOff += maMouseOff.X()+(maStartRect.Right()-maStartRect.Left());
1220 if ( nXOff < mnMinWidth )
1221 nXOff = mnMinWidth;
1222 if ( nXOff > mnMaxWidth )
1223 nXOff = mnMaxWidth;
1224 maRect.Right() = maStartRect.Left()+nXOff;
1226 else
1228 maRect.SetPos( rPos );
1229 maRect.Move( maMouseOff.X(), maMouseOff.Y() );
1231 mpDragBox->ShowTracking( maRect );
1235 void ImplTBDragMgr::EndDragging( bool bOK )
1237 mpDragBox->HideTracking();
1238 if (mpDragBox->IsMouseCaptured())
1239 mpDragBox->ReleaseMouse();
1240 mpDragBox->mbDragging = false;
1241 mbShowDragRect = false;
1242 Application::RemoveAccel( &maAccel );
1244 if ( mnLineMode )
1246 if ( !bOK )
1248 mpDragBox->mnDockLines = mnStartLines;
1249 mpDragBox->EndDocking( maStartRect, false );
1251 else
1252 mpDragBox->EndDocking( maRect, false );
1253 mnLineMode = 0;
1254 mnStartLines = 0;
1256 else
1258 sal_uInt16 nTempItem = mpDragBox->mnConfigItem;
1259 if ( nTempItem )
1261 mpDragBox->mnConfigItem = 0;
1262 if ( !mbResizeMode )
1263 mpDragBox->Invalidate( mpDragBox->GetItemRect( nTempItem ) );
1266 if ( bOK && (maRect != maStartRect) )
1268 if ( mbResizeMode )
1270 ImplToolItem* pItem = mpDragBox->ImplGetItem( nTempItem );
1271 Size aSize = pItem->mpWindow->GetSizePixel();
1272 aSize.Width() = maRect.GetWidth();
1273 pItem->mpWindow->SetSizePixel( aSize );
1275 // re-calculate and show ToolBox
1276 mpDragBox->ImplInvalidate( true );
1278 else
1280 Point aOff = mpDragBox->OutputToScreenPixel( Point() );
1281 Rectangle aScreenRect( maRect );
1282 aScreenRect.Move( aOff.X(), aOff.Y() );
1283 ToolBox* pDropBox = FindToolBox( aScreenRect );
1284 if ( pDropBox )
1286 // Determine search position
1287 Point aPos;
1288 if ( pDropBox->mbHorz )
1290 aPos.X() = aScreenRect.Left()-TB_CUSTOMIZE_OFFSET;
1291 aPos.Y() = aScreenRect.Center().Y();
1293 else
1295 aPos.X() = aScreenRect.Center().X();
1296 aPos.Y() = aScreenRect.Top()-TB_CUSTOMIZE_OFFSET;
1299 aPos = pDropBox->ScreenToOutputPixel( aPos );
1300 ToolBox::ImplFindItemPos( pDropBox, aPos );
1304 mpCustomizeData = nullptr;
1305 mbResizeMode = false;
1306 mpDragBox->Deactivate();
1309 mpDragBox = nullptr;
1312 void ImplTBDragMgr::UpdateDragRect()
1314 // Only update if we're already dragging
1315 if ( !mbShowDragRect )
1316 return;
1318 mpDragBox->ShowTracking( maRect );
1321 IMPL_LINK( ImplTBDragMgr, SelectHdl, Accelerator&, rAccel, void )
1323 if ( rAccel.GetCurItemId() == KEY_ESCAPE )
1324 EndDragging( false );
1325 else
1326 EndDragging();
1329 void ToolBox::ImplInitToolBoxData()
1331 // initialize variables
1332 ImplGetWindowImpl()->mbToolBox = true;
1333 mpData = new ImplToolBoxPrivateData;
1334 mpFloatWin = nullptr;
1335 mnDX = 0;
1336 mnDY = 0;
1337 mnMaxItemWidth = 0;
1338 mnMaxItemHeight = 0;
1339 mnWinHeight = 0;
1340 mnLeftBorder = 0;
1341 mnTopBorder = 0;
1342 mnRightBorder = 0;
1343 mnBottomBorder = 0;
1344 mnLastResizeDY = 0;
1345 mnOutStyle = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF
1346 mnHighItemId = 0;
1347 mnCurItemId = 0;
1348 mnDownItemId = 0;
1349 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
1350 mnFocusPos = TOOLBOX_ITEM_NOTFOUND; // current position during keyboard access
1351 mnLines = 1;
1352 mnCurLine = 1;
1353 mnCurLines = 1;
1354 mnVisLines = 1;
1355 mnFloatLines = 0;
1356 mnDockLines = 0;
1357 mnConfigItem = 0;
1358 mnMouseClicks = 0;
1359 mnMouseModifier = 0;
1360 mbDrag = false;
1361 mbSelection = false;
1362 mbCommandDrag = false;
1363 mbUpper = false;
1364 mbLower = false;
1365 mbIn = false;
1366 mbCalc = true;
1367 mbFormat = false;
1368 mbFullPaint = false;
1369 mbHorz = true;
1370 mbScroll = false;
1371 mbLastFloatMode = false;
1372 mbCustomize = false;
1373 mbCustomizeMode = false;
1374 mbDragging = false;
1375 mbIsShift = false;
1376 mbIsKeyEvent = false;
1377 mbChangingHighlight = false;
1378 mbImagesMirrored = false;
1379 meButtonType = ButtonType::SYMBOLONLY;
1380 meAlign = WindowAlign::Top;
1381 meDockAlign = WindowAlign::Top;
1382 meLastStyle = PointerStyle::Arrow;
1383 mnWinStyle = 0;
1384 meLayoutMode = ToolBoxLayoutMode::Normal;
1385 meTextPosition = ToolBoxTextPosition::Right;
1386 mnLastFocusItemId = 0;
1387 mnKeyModifier = 0;
1388 mnActivateCount = 0;
1389 mnImagesRotationAngle = 0;
1390 mpStatusListener = new VclStatusListener<ToolBox>(this, ".uno:ImageOrientation");
1392 mpIdle = new Idle("vcl::ToolBox maIdle update");
1393 mpIdle->SetPriority( SchedulerPriority::RESIZE );
1394 mpIdle->SetIdleHdl( LINK( this, ToolBox, ImplUpdateHdl ) );
1396 // set timeout and handler for dropdown items
1397 mpData->maDropdownTimer.SetTimeout( 250 );
1398 mpData->maDropdownTimer.SetTimeoutHdl( LINK( this, ToolBox, ImplDropdownLongClickHdl ) );
1399 mpData->maDropdownTimer.SetDebugName( "vcl::ToolBox mpData->maDropdownTimer" );
1402 void ToolBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
1404 // initialize variables
1405 mbScroll = (nStyle & WB_SCROLL) != 0;
1406 mnWinStyle = nStyle;
1408 DockingWindow::ImplInit( pParent, nStyle & ~(WB_BORDER) );
1410 // dockingwindow's ImplInit removes some bits, so restore them here to allow keyboard handling for toolbars
1411 ImplGetWindowImpl()->mnStyle |= WB_TABSTOP|WB_NODIALOGCONTROL; // always set WB_TABSTOP for ToolBars
1412 ImplGetWindowImpl()->mnStyle &= ~WB_DIALOGCONTROL;
1414 ImplInitSettings(true, true, true);
1417 void ToolBox::ApplySettings(vcl::RenderContext& rRenderContext)
1419 mpData->mbNativeButtons = rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ControlPart::Button);
1421 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1423 // Font
1424 vcl::Font aFont = rStyleSettings.GetToolFont();
1425 if (IsControlFont())
1426 aFont.Merge(GetControlFont());
1427 SetZoomedPointFont(rRenderContext, aFont);
1429 // ControlForeground
1430 Color aColor;
1431 if (IsControlForeground())
1432 aColor = GetControlForeground();
1433 else if (Window::GetStyle() & WB_3DLOOK)
1434 aColor = rStyleSettings.GetButtonTextColor();
1435 else
1436 aColor = rStyleSettings.GetWindowTextColor();
1437 rRenderContext.SetTextColor(aColor);
1438 rRenderContext.SetTextFillColor();
1440 if (IsControlBackground())
1442 aColor = GetControlBackground();
1443 SetBackground( aColor );
1444 SetPaintTransparent(false);
1445 SetParentClipMode();
1447 else
1449 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ControlPart::Entire)
1450 || (GetAlign() == WindowAlign::Top && !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty())
1451 || (GetAlign() == WindowAlign::Bottom && !Application::GetSettings().GetStyleSettings().GetPersonaFooter().IsEmpty()))
1453 rRenderContext.SetBackground();
1454 rRenderContext.SetTextColor(rStyleSettings.GetToolTextColor());
1455 SetPaintTransparent(true);
1456 SetParentClipMode(ParentClipMode::NoClip);
1457 mpData->maDisplayBackground = Wallpaper(rStyleSettings.GetFaceColor());
1459 else
1461 if (Window::GetStyle() & WB_3DLOOK)
1462 aColor = rStyleSettings.GetFaceColor();
1463 else
1464 aColor = rStyleSettings.GetWindowColor();
1466 rRenderContext.SetBackground(aColor);
1467 SetPaintTransparent(false);
1468 SetParentClipMode();
1473 void ToolBox::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1475 mpData->mbNativeButtons = IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button );
1477 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1479 if (bFont)
1481 vcl::Font aFont = rStyleSettings.GetToolFont();
1482 if (IsControlFont())
1483 aFont.Merge(GetControlFont());
1484 SetZoomedPointFont(*this, aFont);
1487 if (bForeground || bFont)
1489 Color aColor;
1490 if (IsControlForeground())
1491 aColor = GetControlForeground();
1492 else if (Window::GetStyle() & WB_3DLOOK)
1493 aColor = rStyleSettings.GetButtonTextColor();
1494 else
1495 aColor = rStyleSettings.GetWindowTextColor();
1496 SetTextColor(aColor);
1497 SetTextFillColor();
1500 if (bBackground)
1502 Color aColor;
1503 if (IsControlBackground())
1505 aColor = GetControlBackground();
1506 SetBackground( aColor );
1507 SetPaintTransparent(false);
1508 SetParentClipMode();
1510 else
1512 if (IsNativeControlSupported(ControlType::Toolbar, ControlPart::Entire)
1513 || (GetAlign() == WindowAlign::Top && !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty())
1514 || (GetAlign() == WindowAlign::Bottom && !Application::GetSettings().GetStyleSettings().GetPersonaFooter().IsEmpty()))
1516 SetBackground();
1517 SetTextColor(rStyleSettings.GetMenuBarTextColor());
1518 SetPaintTransparent( true );
1519 SetParentClipMode( ParentClipMode::NoClip );
1520 mpData->maDisplayBackground = Wallpaper( rStyleSettings.GetFaceColor() );
1522 else
1524 if (Window::GetStyle() & WB_3DLOOK)
1525 aColor = rStyleSettings.GetFaceColor();
1526 else
1527 aColor = rStyleSettings.GetWindowColor();
1529 SetBackground(aColor);
1530 SetPaintTransparent(false);
1531 SetParentClipMode();
1537 void ToolBox::doDeferredInit(WinBits nBits)
1539 VclPtr<vcl::Window> pParent = mpDialogParent;
1540 mpDialogParent = nullptr;
1541 ImplInit(pParent, nBits);
1542 mbIsDefferedInit = false;
1545 ToolBox::ToolBox( vcl::Window* pParent, WinBits nStyle ) :
1546 DockingWindow( WINDOW_TOOLBOX )
1548 ImplInitToolBoxData();
1549 ImplInit( pParent, nStyle );
1552 ToolBox::ToolBox(vcl::Window* pParent, const OString& rID,
1553 const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
1554 : DockingWindow(WINDOW_TOOLBOX)
1556 ImplInitToolBoxData();
1558 loadUI(pParent, rID, rUIXMLDescription, rFrame);
1560 // calculate size of floating windows and switch if the
1561 // toolbox is initially in floating mode
1562 if ( ImplIsFloatingMode() )
1563 mbHorz = true;
1564 else
1565 Resize();
1567 if (!(GetStyle() & WB_HIDE))
1568 Show();
1571 ToolBox::~ToolBox()
1573 disposeOnce();
1576 void ToolBox::dispose()
1578 // custom menu event still running?
1579 if( mpData && mpData->mnEventId )
1580 Application::RemoveUserEvent( mpData->mnEventId );
1582 // #103005# make sure our activate/deactivate balance is right
1583 while( mnActivateCount > 0 )
1584 Deactivate();
1586 // terminate popupmode if the floating window is
1587 // still connected
1588 if ( mpFloatWin )
1589 mpFloatWin->EndPopupMode( FloatWinPopupEndFlags::Cancel );
1590 mpFloatWin = nullptr;
1592 // delete private data
1593 delete mpData;
1594 mpData = nullptr;
1596 // remove the lists when there are no more toolbox references to
1597 // the lists
1598 ImplSVData* pSVData = ImplGetSVData();
1599 if ( pSVData->maCtrlData.mpTBDragMgr )
1601 // remove if in TBDrag-Manager
1602 if ( mbCustomize )
1603 pSVData->maCtrlData.mpTBDragMgr->erase( this );
1605 if ( !pSVData->maCtrlData.mpTBDragMgr->size() )
1607 delete pSVData->maCtrlData.mpTBDragMgr;
1608 pSVData->maCtrlData.mpTBDragMgr = nullptr;
1612 if (mpStatusListener.is())
1613 mpStatusListener->dispose();
1615 mpFloatWin.clear();
1617 delete mpIdle;
1618 mpIdle = nullptr;
1620 DockingWindow::dispose();
1623 ImplToolItem* ToolBox::ImplGetItem( sal_uInt16 nItemId ) const
1625 if (!mpData)
1626 return nullptr;
1628 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
1629 while ( it != mpData->m_aItems.end() )
1631 if ( it->mnId == nItemId )
1632 return &(*it);
1633 ++it;
1636 return nullptr;
1639 static void ImplAddButtonBorder( long &rWidth, long& rHeight, bool bNativeButtons )
1641 rWidth += SMALLBUTTON_HSIZE;
1642 rHeight += SMALLBUTTON_VSIZE;
1644 if( bNativeButtons )
1646 // give more border space for rounded buttons
1647 rWidth += 2;
1648 rHeight += 4;
1652 bool ToolBox::ImplCalcItem()
1655 // recalc required ?
1656 if ( !mbCalc )
1657 return false;
1659 ImplDisableFlatButtons();
1661 long nDefWidth;
1662 long nDefHeight;
1663 long nMaxWidth = 0;
1664 long nMaxHeight = 0;
1665 long nMinWidth = 6;
1666 long nMinHeight = 6;
1667 long nDropDownArrowWidth = TB_DROPDOWNARROWWIDTH;
1669 // set defaults if image or text is needed but empty
1670 nDefWidth = GetDefaultImageSize().Width();
1671 nDefHeight = GetDefaultImageSize().Height();
1673 mnWinHeight = 0;
1674 // determine minimum size necessary in NWF
1676 Rectangle aRect( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1677 Rectangle aReg( aRect );
1678 ImplControlValue aVal;
1679 Rectangle aNativeBounds, aNativeContent;
1680 if( IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button ) )
1682 if( GetNativeControlRegion( ControlType::Toolbar, ControlPart::Button,
1683 aReg,
1684 ControlState::ENABLED | ControlState::ROLLOVER,
1685 aVal, OUString(),
1686 aNativeBounds, aNativeContent ) )
1688 aRect = aNativeBounds;
1689 if( aRect.GetWidth() > nMinWidth )
1690 nMinWidth = aRect.GetWidth();
1691 if( aRect.GetHeight() > nMinHeight )
1692 nMinHeight = aRect.GetHeight();
1693 if( nDropDownArrowWidth < nMinWidth )
1694 nDropDownArrowWidth = nMinWidth;
1695 if( nMinWidth > mpData->mnMenuButtonWidth )
1696 mpData->mnMenuButtonWidth = nMinWidth;
1697 else if( nMinWidth < TB_MENUBUTTON_SIZE )
1698 mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE;
1702 // also calculate the area for comboboxes, drop down list boxes and spinfields
1703 // as these are often inserted into toolboxes; set mnWinHeight to the
1704 // greater of those values to prevent toolbar flickering (#i103385#)
1705 aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1706 aReg = aRect;
1707 if( GetNativeControlRegion( ControlType::Combobox, ControlPart::Entire,
1708 aReg,
1709 ControlState::ENABLED | ControlState::ROLLOVER,
1710 aVal, OUString(),
1711 aNativeBounds, aNativeContent ) )
1713 aRect = aNativeBounds;
1714 if( aRect.GetHeight() > mnWinHeight )
1715 mnWinHeight = aRect.GetHeight();
1717 aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1718 aReg = aRect;
1719 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire,
1720 aReg,
1721 ControlState::ENABLED | ControlState::ROLLOVER,
1722 aVal, OUString(),
1723 aNativeBounds, aNativeContent ) )
1725 aRect = aNativeBounds;
1726 if( aRect.GetHeight() > mnWinHeight )
1727 mnWinHeight = aRect.GetHeight();
1729 aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1730 aReg = aRect;
1731 if( GetNativeControlRegion( ControlType::Spinbox, ControlPart::Entire,
1732 aReg,
1733 ControlState::ENABLED | ControlState::ROLLOVER,
1734 aVal, OUString(),
1735 aNativeBounds, aNativeContent ) )
1737 aRect = aNativeBounds;
1738 if( aRect.GetHeight() > mnWinHeight )
1739 mnWinHeight = aRect.GetHeight();
1743 if ( ! mpData->m_aItems.empty() )
1745 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
1746 while ( it != mpData->m_aItems.end() )
1748 it->mbVisibleText = false; // indicates if text will definitely be drawn, influences dropdown pos
1750 if ( it->meType == ToolBoxItemType::BUTTON )
1752 bool bImage;
1753 bool bText;
1755 // check if image and/or text exists
1756 if ( !(it->maImage) )
1757 bImage = false;
1758 else
1759 bImage = true;
1760 if ( it->maText.isEmpty() )
1761 bText = false;
1762 else
1763 bText = true;
1764 ButtonType tmpButtonType = determineButtonType( &(*it), meButtonType ); // default to toolbox setting
1765 if ( bImage || bText )
1768 it->mbEmptyBtn = false;
1770 if ( tmpButtonType == ButtonType::SYMBOLONLY )
1772 // we're drawing images only
1773 if ( bImage || !bText )
1775 it->maItemSize = it->maImage.GetSizePixel();
1777 else
1779 it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET,
1780 GetTextHeight() );
1781 it->mbVisibleText = true;
1784 else if ( tmpButtonType == ButtonType::TEXT )
1786 // we're drawing text only
1787 if ( bText || !bImage )
1789 it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET,
1790 GetTextHeight() );
1791 it->mbVisibleText = true;
1793 else
1795 it->maItemSize = it->maImage.GetSizePixel();
1798 else
1800 // we're drawing images and text
1801 it->maItemSize.Width() = bText ? GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET : 0;
1802 it->maItemSize.Height() = bText ? GetTextHeight() : 0;
1804 if ( meTextPosition == ToolBoxTextPosition::Right )
1806 // leave space between image and text
1807 if( bText )
1808 it->maItemSize.Width() += TB_IMAGETEXTOFFSET;
1810 // image and text side by side
1811 it->maItemSize.Width() += it->maImage.GetSizePixel().Width();
1812 if ( it->maImage.GetSizePixel().Height() > it->maItemSize.Height() )
1813 it->maItemSize.Height() = it->maImage.GetSizePixel().Height();
1815 else
1817 // leave space between image and text
1818 if( bText )
1819 it->maItemSize.Height() += TB_IMAGETEXTOFFSET;
1821 // text below image
1822 it->maItemSize.Height() += it->maImage.GetSizePixel().Height();
1823 if ( it->maImage.GetSizePixel().Width() > it->maItemSize.Width() )
1824 it->maItemSize.Width() = it->maImage.GetSizePixel().Width();
1827 it->mbVisibleText = bText;
1830 else
1831 { // no image and no text
1832 it->maItemSize = Size( nDefWidth, nDefHeight );
1833 it->mbEmptyBtn = true;
1836 // save the content size
1837 it->maContentSize = it->maItemSize;
1839 // if required, take window height into consideration
1840 if ( it->mpWindow )
1842 long nHeight = it->mpWindow->GetSizePixel().Height();
1843 if ( nHeight > mnWinHeight )
1844 mnWinHeight = nHeight;
1847 // add in drop down arrow
1848 if( it->mnBits & ToolBoxItemBits::DROPDOWN )
1850 if ( meTextPosition == ToolBoxTextPosition::Right )
1852 it->maItemSize.Width() += nDropDownArrowWidth;
1853 it->mnDropDownArrowWidth = nDropDownArrowWidth;
1855 else
1857 it->maItemSize.Height() += nDropDownArrowWidth;
1858 it->mnDropDownArrowWidth = nDropDownArrowWidth;
1862 // text items will be rotated in vertical mode
1863 // -> swap width and height
1864 if( it->mbVisibleText && !mbHorz )
1866 long tmp = it->maItemSize.Width();
1867 it->maItemSize.Width() = it->maItemSize.Height();
1868 it->maItemSize.Height() = tmp;
1870 tmp = it->maContentSize.Width();
1871 it->maContentSize.Width() = it->maContentSize.Height();
1872 it->maContentSize.Height() = tmp;
1875 else if ( it->meType == ToolBoxItemType::SPACE )
1877 it->maItemSize = Size( nDefWidth, nDefHeight );
1878 it->maContentSize = it->maItemSize;
1881 if ( it->meType == ToolBoxItemType::BUTTON || it->meType == ToolBoxItemType::SPACE )
1883 // add borders
1884 ImplAddButtonBorder( it->maItemSize.Width(), it->maItemSize.Height(), mpData->mbNativeButtons );
1886 if( it->meType == ToolBoxItemType::BUTTON )
1888 long nMinW = std::max(nMinWidth, it->maMinimalItemSize.Width());
1889 long nMinH = std::max(nMinHeight, it->maMinimalItemSize.Height());
1891 long nGrowContentWidth = 0;
1892 long nGrowContentHeight = 0;
1894 if( it->maItemSize.Width() < nMinW )
1896 nGrowContentWidth = nMinW - it->maItemSize.Width();
1897 it->maItemSize.Width() = nMinW;
1899 if( it->maItemSize.Height() < nMinH )
1901 nGrowContentHeight = nMinH - it->maItemSize.Height();
1902 it->maItemSize.Height() = nMinH;
1905 // grow the content size by the additional available space
1906 it->maContentSize.Width() += nGrowContentWidth;
1907 it->maContentSize.Height() += nGrowContentHeight;
1910 // keep track of max item size
1911 if ( it->maItemSize.Width() > nMaxWidth )
1912 nMaxWidth = it->maItemSize.Width();
1913 if ( it->maItemSize.Height() > nMaxHeight )
1914 nMaxHeight = it->maItemSize.Height();
1917 ++it;
1920 else
1922 nMaxWidth = nDefWidth;
1923 nMaxHeight = nDefHeight;
1925 ImplAddButtonBorder( nMaxWidth, nMaxHeight, mpData->mbNativeButtons );
1928 if( !ImplIsFloatingMode() && GetToolboxButtonSize() != ToolBoxButtonSize::DontCare
1929 && ( meTextPosition == ToolBoxTextPosition::Right ) )
1931 // make sure all vertical toolbars have the same width and horizontal have the same height
1932 // this depends on the used button sizes
1933 // as this is used for alignement of multiple toolbars
1934 // it is only required for docked toolbars
1936 long nFixedWidth = nDefWidth+nDropDownArrowWidth;
1937 long nFixedHeight = nDefHeight;
1938 ImplAddButtonBorder( nFixedWidth, nFixedHeight, mpData->mbNativeButtons );
1940 if( mbHorz )
1941 nMaxHeight = nFixedHeight;
1942 else
1943 nMaxWidth = nFixedWidth;
1946 mbCalc = false;
1947 mbFormat = true;
1949 // do we have to recalc the sizes ?
1950 if ( (nMaxWidth != mnMaxItemWidth) || (nMaxHeight != mnMaxItemHeight) )
1952 mnMaxItemWidth = nMaxWidth;
1953 mnMaxItemHeight = nMaxHeight;
1955 return true;
1957 else
1958 return false;
1961 sal_uInt16 ToolBox::ImplCalcBreaks( long nWidth, long* pMaxLineWidth, bool bCalcHorz )
1963 sal_uLong nLineStart = 0;
1964 sal_uLong nGroupStart = 0;
1965 long nLineWidth = 0;
1966 long nCurWidth;
1967 long nLastGroupLineWidth = 0;
1968 long nMaxLineWidth = 0;
1969 sal_uInt16 nLines = 1;
1970 bool bWindow;
1971 bool bBreak = false;
1972 long nWidthTotal = nWidth;
1973 long nMenuWidth = 0;
1975 // when docked the menubutton will be in the first line
1976 if( IsMenuEnabled() && !ImplIsFloatingMode() )
1977 nMenuWidth = mpData->maMenubuttonItem.maItemSize.Width();
1979 // we need to know which item is the last visible one to be able to add
1980 // the menu width in case we are unable to show all the items
1981 std::vector< ImplToolItem >::iterator it, lastVisible;
1982 for ( it = mpData->m_aItems.begin(); it != mpData->m_aItems.end(); ++it )
1984 if ( it->mbVisible )
1985 lastVisible = it;
1988 it = mpData->m_aItems.begin();
1989 while ( it != mpData->m_aItems.end() )
1991 it->mbBreak = bBreak;
1992 bBreak = false;
1994 if ( it->mbVisible )
1996 bWindow = false;
1997 bBreak = false;
1998 nCurWidth = 0;
2000 if ( it->meType == ToolBoxItemType::BUTTON || it->meType == ToolBoxItemType::SPACE )
2002 if ( bCalcHorz )
2003 nCurWidth = it->maItemSize.Width();
2004 else
2005 nCurWidth = it->maItemSize.Height();
2007 if ( it->mpWindow && bCalcHorz )
2009 long nWinItemWidth = it->mpWindow->GetSizePixel().Width();
2010 if ( !mbScroll || (nWinItemWidth <= nWidthTotal) )
2012 nCurWidth = nWinItemWidth;
2013 bWindow = true;
2015 else
2017 if ( it->mbEmptyBtn )
2019 nCurWidth = 0;
2024 // in case we are able to show all the items, we do not want
2025 // to show the toolbar's menu; otherwise yes
2026 if ( ( ( it == lastVisible ) && (nLineWidth+nCurWidth > nWidthTotal) && mbScroll ) ||
2027 ( ( it != lastVisible ) && (nLineWidth+nCurWidth+nMenuWidth > nWidthTotal) && mbScroll ) )
2028 bBreak = true;
2030 else if ( it->meType == ToolBoxItemType::SEPARATOR )
2032 nCurWidth = it->mnSepSize;
2033 if ( !ImplIsFloatingMode() && ( it != lastVisible ) && (nLineWidth+nCurWidth+nMenuWidth > nWidthTotal) )
2034 bBreak = true;
2036 // treat breaks as separators, except when using old style toolbars (ie. no menu button)
2037 else if ( (it->meType == ToolBoxItemType::BREAK) && !IsMenuEnabled() )
2038 bBreak = true;
2040 if ( bBreak )
2042 nLines++;
2044 // Add break before the entire group or take group apart?
2045 if ( (it->meType == ToolBoxItemType::BREAK) ||
2046 (nLineStart == nGroupStart) )
2048 if ( nLineWidth > nMaxLineWidth )
2049 nMaxLineWidth = nLineWidth;
2051 nLineWidth = 0;
2052 nLineStart = it - mpData->m_aItems.begin();
2053 nGroupStart = nLineStart;
2054 it->mbBreak = true;
2055 bBreak = false;
2057 else
2059 if ( nLastGroupLineWidth > nMaxLineWidth )
2060 nMaxLineWidth = nLastGroupLineWidth;
2062 // if the break is added before the group, set it to
2063 // beginning of line and re-calculate
2064 nLineWidth = 0;
2065 nLineStart = nGroupStart;
2066 it = mpData->m_aItems.begin() + nGroupStart;
2067 continue;
2070 else
2072 if( ImplIsFloatingMode() || !IsMenuEnabled() ) // no group breaking when being docked single-line
2074 if ( (it->meType != ToolBoxItemType::BUTTON) || bWindow )
2076 // found separator or break
2077 nLastGroupLineWidth = nLineWidth;
2078 nGroupStart = it - mpData->m_aItems.begin();
2079 if ( !bWindow )
2080 nGroupStart++;
2085 nLineWidth += nCurWidth;
2088 ++it;
2091 if ( pMaxLineWidth )
2093 if ( nLineWidth > nMaxLineWidth )
2094 nMaxLineWidth = nLineWidth;
2096 if( ImplIsFloatingMode() && !ImplIsInPopupMode() )
2098 // leave enough space to display buttons in the decoration
2099 long aMinWidth = 2 * GetSettings().GetStyleSettings().GetFloatTitleHeight();
2100 if( nMaxLineWidth < aMinWidth )
2101 nMaxLineWidth = aMinWidth;
2103 *pMaxLineWidth = nMaxLineWidth;
2106 return nLines;
2109 Size ToolBox::ImplGetOptimalFloatingSize()
2111 if( !ImplIsFloatingMode() )
2112 return Size();
2114 Size aCurrentSize( mnDX, mnDY );
2115 Size aSize1( aCurrentSize );
2116 Size aSize2( aCurrentSize );
2118 // try to preserve current height
2120 // calc number of floating lines for current window height
2121 sal_uInt16 nFloatLinesHeight = ImplCalcLines( this, mnDY );
2122 // calc window size according to this number
2123 aSize1 = ImplCalcFloatSize( this, nFloatLinesHeight );
2125 if( aCurrentSize == aSize1 )
2126 return aSize1;
2128 // try to preserve current width
2130 long nLineHeight = ( mnWinHeight > mnMaxItemHeight ) ? mnWinHeight : mnMaxItemHeight;
2131 int nBorderX = 2*TB_BORDER_OFFSET1 + mnLeftBorder + mnRightBorder;
2132 int nBorderY = 2*TB_BORDER_OFFSET2 + mnTopBorder + mnBottomBorder;
2133 Size aSz( aCurrentSize );
2134 long maxX;
2135 sal_uInt16 nLines = ImplCalcBreaks( aSz.Width()-nBorderX, &maxX, mbHorz );
2137 sal_uInt16 manyLines = 1000;
2138 Size aMinimalFloatSize = ImplCalcFloatSize( this, manyLines );
2140 aSz.Height() = nBorderY + nLineHeight * nLines;
2141 // line space when more than one line
2142 if ( mnWinStyle & WB_LINESPACING )
2143 aSz.Height() += (nLines-1)*TB_LINESPACING;
2145 aSz.Width() = nBorderX + maxX;
2147 // avoid clipping of any items
2148 if( aSz.Width() < aMinimalFloatSize.Width() )
2149 aSize2 = ImplCalcFloatSize( this, nLines );
2150 else
2151 aSize2 = aSz;
2153 if( aCurrentSize == aSize2 )
2154 return aSize2;
2156 // set the size with the smallest delta as the current size
2157 long dx1 = std::abs( mnDX - aSize1.Width() );
2158 long dy1 = std::abs( mnDY - aSize1.Height() );
2160 long dx2 = std::abs( mnDX - aSize2.Width() );
2161 long dy2 = std::abs( mnDY - aSize2.Height() );
2163 if( dx1*dy1 < dx2*dy2 )
2164 aCurrentSize = aSize1;
2165 else
2166 aCurrentSize = aSize2;
2168 return aCurrentSize;
2171 namespace
2173 void lcl_hideDoubleSeparators( std::vector< ImplToolItem >& rItems )
2175 bool bLastSep( true );
2176 std::vector< ImplToolItem >::iterator it;
2177 for ( it = rItems.begin(); it != rItems.end(); ++it )
2179 if ( it->meType == ToolBoxItemType::SEPARATOR )
2181 it->mbVisible = false;
2182 if ( !bLastSep )
2184 // check if any visible items have to appear behind it
2185 std::vector< ImplToolItem >::iterator temp_it;
2186 for ( temp_it = it+1; temp_it != rItems.end(); ++temp_it )
2188 if ( ((temp_it->meType == ToolBoxItemType::BUTTON) &&
2189 temp_it->mbVisible) )
2191 it->mbVisible = true;
2192 break;
2196 bLastSep = true;
2198 else if ( it->mbVisible )
2199 bLastSep = false;
2204 void ToolBox::ImplFormat( bool bResize )
2206 // Has to re-formatted
2207 if ( !mbFormat )
2208 return;
2210 mpData->ImplClearLayoutData();
2212 // recalculate positions and sizes
2213 Rectangle aEmptyRect;
2214 long nLineSize;
2215 long nLeft;
2216 long nTop;
2217 long nMax; // width of layoutarea in pixels
2218 sal_uInt16 nFormatLine;
2219 bool bMustFullPaint;
2221 std::vector< ImplToolItem >::iterator it;
2223 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
2224 bool bIsInPopupMode = ImplIsInPopupMode();
2226 maFloatSizes.clear();
2228 // compute border sizes
2229 ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder, mnRightBorder, mnBottomBorder, this );
2231 // update drag area (where the 'grip' will be placed)
2232 Rectangle aOldDragRect;
2233 if( pWrapper )
2234 aOldDragRect = pWrapper->GetDragArea();
2235 ImplUpdateDragArea( this );
2237 if ( ImplCalcItem() )
2238 bMustFullPaint = true;
2239 else
2240 bMustFullPaint = false;
2242 // calculate new size during interactive resize or
2243 // set computed size when formatting only
2244 if ( ImplIsFloatingMode() )
2246 if ( bResize )
2247 mnFloatLines = ImplCalcLines( this, mnDY );
2248 else
2249 SetOutputSizePixel( ImplGetOptimalFloatingSize() );
2252 // Horizontal
2253 if ( mbHorz )
2255 long nBottom;
2256 // nLineSize: height of a single line, will fit highest item
2257 nLineSize = mnMaxItemHeight;
2259 if ( mnWinHeight > mnMaxItemHeight )
2260 nLineSize = mnWinHeight;
2262 if ( mbScroll )
2264 nMax = mnDX;
2265 mnVisLines = ImplCalcLines( this, mnDY );
2267 else
2269 // layout over all lines
2270 mnVisLines = mnLines;
2271 nMax = TB_MAXNOSCROLL;
2274 // add in all border offsets
2275 if ( mnWinStyle & WB_BORDER )
2277 nLeft = TB_BORDER_OFFSET1 + mnLeftBorder;
2278 nTop = TB_BORDER_OFFSET2 + mnTopBorder;
2279 nBottom = TB_BORDER_OFFSET1 + mnBottomBorder;
2280 nMax -= nLeft + TB_BORDER_OFFSET1 + mnRightBorder;
2282 else
2284 nLeft = 0;
2285 nTop = 0;
2286 nBottom = 0;
2289 // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
2290 // we have to center all items in the window height
2291 if( IsMenuEnabled() && !ImplIsFloatingMode() )
2293 long nWinHeight = mnDY - nTop - nBottom;
2294 if( nWinHeight > nLineSize )
2295 nLineSize = nWinHeight;
2298 else
2300 long nRight;
2301 nLineSize = mnMaxItemWidth;
2303 if ( mbScroll )
2305 mnVisLines = ImplCalcLines( this, mnDX );
2306 nMax = mnDY;
2308 else
2310 mnVisLines = mnLines;
2311 nMax = TB_MAXNOSCROLL;
2314 if ( mnWinStyle & WB_BORDER )
2316 nTop = TB_BORDER_OFFSET1 + mnTopBorder;
2317 nLeft = TB_BORDER_OFFSET2 + mnLeftBorder;
2318 nRight = TB_BORDER_OFFSET2 + mnRightBorder;
2319 nMax -= nTop + TB_BORDER_OFFSET1 + mnBottomBorder;
2321 else
2323 nLeft = 0;
2324 nTop = 0;
2325 nRight = 0;
2328 // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
2329 // we have to center all items in the window height
2330 if( !ImplIsFloatingMode() && IsMenuEnabled() )
2332 long nWinWidth = mnDX - nLeft - nRight;
2333 if( nWinWidth > nLineSize )
2334 nLineSize = nWinWidth;
2338 // no calculation if the window has no size (nMax=0)
2339 // non scrolling toolboxes must be computed though
2340 if ( (nMax <= 0) && mbScroll )
2342 mnVisLines = 1;
2343 mnCurLine = 1;
2344 mnCurLines = 1;
2346 it = mpData->m_aItems.begin();
2347 while ( it != mpData->m_aItems.end() )
2349 it->maRect = aEmptyRect;
2350 ++it;
2353 maLowerRect = aEmptyRect;
2354 maUpperRect = aEmptyRect;
2356 else
2358 // init start values
2359 long nX = nLeft; // top-left offset
2360 long nY = nTop;
2361 nFormatLine = 1;
2363 // save old scroll rectangles and reset them
2364 Rectangle aOldLowerRect = maLowerRect;
2365 Rectangle aOldUpperRect = maUpperRect;
2366 Rectangle aOldMenubuttonRect = mpData->maMenubuttonItem.maRect;
2367 maUpperRect = aEmptyRect;
2368 maLowerRect = aEmptyRect;
2369 mpData->maMenubuttonItem.maRect = aEmptyRect;
2371 // do we have any toolbox items at all ?
2372 if ( !mpData->m_aItems.empty() || IsMenuEnabled() )
2374 lcl_hideDoubleSeparators( mpData->m_aItems );
2376 // compute line breaks and visible lines give the current window width (nMax)
2377 // the break indicators will be stored within each item (it->mbBreak)
2378 mnCurLines = ImplCalcBreaks( nMax, nullptr, mbHorz );
2380 // check for scrollbar buttons or dropdown menu
2381 // (if a menu is enabled, this will be used to store clipped
2382 // items and no scroll buttons will appear)
2383 if ( (!ImplIsFloatingMode() && (mnCurLines > mnVisLines) && mbScroll ) ||
2384 IsMenuEnabled() )
2386 // compute linebreaks again, incorporating scrollbar buttons
2387 if( !IsMenuEnabled() )
2389 nMax -= TB_SPIN_SIZE+TB_SPIN_OFFSET;
2390 mnCurLines = ImplCalcBreaks( nMax, nullptr, mbHorz );
2393 // compute scroll rectangles or menu button
2394 if ( mbHorz )
2396 if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2398 if( !ImplIsFloatingMode() )
2400 mpData->maMenubuttonItem.maRect.Right() = mnDX - 2;
2401 mpData->maMenubuttonItem.maRect.Top() = nTop;
2402 mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-TB_BORDER_OFFSET2-1;
2404 else
2406 mpData->maMenubuttonItem.maRect.Right() = mnDX - mnRightBorder-TB_BORDER_OFFSET1-1;
2407 mpData->maMenubuttonItem.maRect.Top() = nTop;
2408 mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-TB_BORDER_OFFSET2-1;
2410 mpData->maMenubuttonItem.maRect.Left() = mpData->maMenubuttonItem.maRect.Right() - mpData->mnMenuButtonWidth;
2412 else
2414 maUpperRect.Left() = nLeft+nMax+TB_SPIN_OFFSET;
2415 maUpperRect.Right() = maUpperRect.Left()+TB_SPIN_SIZE-1;
2416 maUpperRect.Top() = nTop;
2417 maLowerRect.Bottom() = mnDY-mnBottomBorder-TB_BORDER_OFFSET2-1;
2418 maLowerRect.Left() = maUpperRect.Left();
2419 maLowerRect.Right() = maUpperRect.Right();
2420 maUpperRect.Bottom() = maUpperRect.Top() +
2421 (maLowerRect.Bottom()-maUpperRect.Top())/2;
2422 maLowerRect.Top() = maUpperRect.Bottom();
2425 else
2427 if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2429 if( !ImplIsFloatingMode() )
2431 mpData->maMenubuttonItem.maRect.Bottom() = mnDY - 2;
2432 mpData->maMenubuttonItem.maRect.Left() = nLeft;
2433 mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-TB_BORDER_OFFSET2-1;
2435 else
2437 mpData->maMenubuttonItem.maRect.Bottom() = mnDY - mnBottomBorder-TB_BORDER_OFFSET1-1;
2438 mpData->maMenubuttonItem.maRect.Left() = nLeft;
2439 mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-TB_BORDER_OFFSET2-1;
2441 mpData->maMenubuttonItem.maRect.Top() = mpData->maMenubuttonItem.maRect.Bottom() - mpData->mnMenuButtonWidth;
2443 else
2445 maUpperRect.Top() = nTop+nMax+TB_SPIN_OFFSET;
2446 maUpperRect.Bottom() = maUpperRect.Top()+TB_SPIN_SIZE-1;
2447 maUpperRect.Left() = nLeft;
2448 maLowerRect.Right() = mnDX-mnRightBorder-TB_BORDER_OFFSET2-1;
2449 maLowerRect.Top() = maUpperRect.Top();
2450 maLowerRect.Bottom() = maUpperRect.Bottom();
2451 maUpperRect.Right() = maUpperRect.Left() +
2452 (maLowerRect.Right()-maUpperRect.Left())/2;
2453 maLowerRect.Left() = maUpperRect.Right();
2458 // no scrolling when there is a "more"-menu
2459 // anything will "fit" in a single line then
2460 if( IsMenuEnabled() )
2461 mnCurLines = 1;
2463 // determine the currently visible line
2464 if ( mnVisLines >= mnCurLines )
2465 mnCurLine = 1;
2466 else if ( mnCurLine+mnVisLines-1 > mnCurLines )
2467 mnCurLine = mnCurLines - (mnVisLines-1);
2469 it = mpData->m_aItems.begin();
2470 while ( it != mpData->m_aItems.end() )
2472 it->mbShowWindow = false;
2474 // check for line break and advance nX/nY accordingly
2475 if ( it->mbBreak )
2477 nFormatLine++;
2479 // increment starting with the second line
2480 if ( nFormatLine > mnCurLine )
2482 if ( mbHorz )
2484 nX = nLeft;
2485 if ( mnWinStyle & WB_LINESPACING )
2486 nY += nLineSize+TB_LINESPACING;
2487 else
2488 nY += nLineSize;
2490 else
2492 nY = nTop;
2493 if ( mnWinStyle & WB_LINESPACING )
2494 nX += nLineSize+TB_LINESPACING;
2495 else
2496 nX += nLineSize;
2501 if ( !it->mbVisible || (nFormatLine < mnCurLine) ||
2502 (nFormatLine > mnCurLine+mnVisLines-1) )
2503 // item is not visible
2504 it->maCalcRect = aEmptyRect;
2505 else
2507 // 1. determine current item width/height
2508 // take window size and orientation into account, because this affects the size of item windows
2510 Size aCurrentItemSize( it->GetSize( mbHorz, mbScroll, nMax, Size(mnMaxItemWidth, mnMaxItemHeight) ) );
2512 // 2. position item rect and use size from step 1
2513 // items will be centered horizontally (if mbHorz) or vertically
2514 // advance nX and nY accordingly
2515 if ( mbHorz )
2517 it->maCalcRect.Left() = nX;
2518 // if special ToolBoxLayoutMode::LockVert lock vertical position
2519 // don't recalculate the vertical position of the item
2520 if ( meLayoutMode == ToolBoxLayoutMode::LockVert && mnLines == 1 )
2522 // Somewhat of a hack here, calc deletes and re-adds
2523 // the sum/assign & ok/cancel items dynamically.
2524 // Because ToolBoxLayoutMode::LockVert effectively prevents
2525 // recalculation of the vertical pos of an item the
2526 // it->maRect.Top() for those newly added items is
2527 // 0. The hack here is that we want to effectively
2528 // recalculate the vertical pos for those added
2529 // items here. ( Note: assume mnMaxItemHeight is
2530 // equal to the LineSize when multibar has a single
2531 // line size )
2532 if ( it->maRect.Top() ||
2533 (it->mpWindow && it->mpWindow->GetType() == WINDOW_CALCINPUTLINE) ) // tdf#83099
2535 it->maCalcRect.Top() = it->maRect.Top();
2537 else
2539 it->maCalcRect.Top() = nY+(mnMaxItemHeight-aCurrentItemSize.Height())/2;
2542 else
2543 it->maCalcRect.Top() = nY+(nLineSize-aCurrentItemSize.Height())/2;
2544 it->maCalcRect.Right() = nX+aCurrentItemSize.Width()-1;
2545 it->maCalcRect.Bottom() = it->maCalcRect.Top()+aCurrentItemSize.Height()-1;
2546 nX += aCurrentItemSize.Width();
2548 else
2550 it->maCalcRect.Left() = nX+(nLineSize-aCurrentItemSize.Width())/2;
2551 it->maCalcRect.Top() = nY;
2552 it->maCalcRect.Right() = it->maCalcRect.Left()+aCurrentItemSize.Width()-1;
2553 it->maCalcRect.Bottom() = nY+aCurrentItemSize.Height()-1;
2554 nY += aCurrentItemSize.Height();
2558 // position window items into calculated item rect
2559 if ( it->mpWindow )
2561 if ( it->mbShowWindow )
2563 Point aPos( it->maCalcRect.Left(), it->maCalcRect.Top() );
2565 assert( it->maCalcRect.Top() >= 0 );
2567 it->mpWindow->SetPosPixel( aPos );
2568 if ( !mbCustomizeMode )
2569 it->mpWindow->Show();
2571 else
2572 it->mpWindow->Hide();
2575 ++it;
2576 } // end of loop over all items
2578 else
2579 // we have no toolbox items
2580 mnCurLines = 1;
2582 if( IsMenuEnabled() && ImplIsFloatingMode() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2584 // custom menu will be the last button in floating mode
2585 ImplToolItem &rIt = mpData->maMenubuttonItem;
2587 if ( mbHorz )
2589 rIt.maRect.Left() = nX+TB_MENUBUTTON_OFFSET;
2590 rIt.maRect.Top() = nY;
2591 rIt.maRect.Right() = rIt.maRect.Left() + mpData->mnMenuButtonWidth;
2592 rIt.maRect.Bottom() = nY+nLineSize-1;
2593 nX += rIt.maItemSize.Width();
2595 else
2597 rIt.maRect.Left() = nX;
2598 rIt.maRect.Top() = nY+TB_MENUBUTTON_OFFSET;
2599 rIt.maRect.Right() = nX+nLineSize-1;
2600 rIt.maRect.Bottom() = rIt.maRect.Top() + mpData->mnMenuButtonWidth;
2601 nY += rIt.maItemSize.Height();
2605 // if toolbox visible trigger paint for changed regions
2606 if ( IsVisible() && !mbFullPaint )
2608 if ( bMustFullPaint )
2610 maPaintRect = Rectangle( mnLeftBorder, mnTopBorder,
2611 mnDX-mnRightBorder, mnDY-mnBottomBorder );
2613 else
2615 if ( aOldLowerRect != maLowerRect )
2617 maPaintRect.Union( maLowerRect );
2618 maPaintRect.Union( aOldLowerRect );
2620 if ( aOldUpperRect != maUpperRect )
2622 maPaintRect.Union( maUpperRect );
2623 maPaintRect.Union( aOldUpperRect );
2625 if ( aOldMenubuttonRect != mpData->maMenubuttonItem.maRect )
2627 maPaintRect.Union( mpData->maMenubuttonItem.maRect );
2628 maPaintRect.Union( aOldMenubuttonRect );
2630 if ( pWrapper && aOldDragRect != pWrapper->GetDragArea() )
2632 maPaintRect.Union( pWrapper->GetDragArea() );
2633 maPaintRect.Union( aOldDragRect );
2636 it = mpData->m_aItems.begin();
2637 while ( it != mpData->m_aItems.end() )
2639 if ( it->maRect != it->maCalcRect )
2641 maPaintRect.Union( it->maRect );
2642 maPaintRect.Union( it->maCalcRect );
2644 ++it;
2648 Invalidate( maPaintRect );
2651 // store the new calculated item rects
2652 maPaintRect = aEmptyRect;
2653 it = mpData->m_aItems.begin();
2654 while ( it != mpData->m_aItems.end() )
2656 it->maRect = it->maCalcRect;
2657 ++it;
2661 // indicate formatting is done
2662 mbFormat = false;
2665 IMPL_LINK_NOARG(ToolBox, ImplDropdownLongClickHdl, Timer *, void)
2667 if (mnCurPos != TOOLBOX_ITEM_NOTFOUND &&
2668 (mpData->m_aItems[ mnCurPos ].mnBits & ToolBoxItemBits::DROPDOWN))
2670 mpData->mbDropDownByKeyboard = false;
2671 mpData->maDropdownClickHdl.Call( this );
2673 // do not reset data if the dropdown handler opened a floating window
2674 // see ImplFloatControl()
2675 if( !mpFloatWin )
2677 // no floater was opened
2678 Deactivate();
2679 InvalidateItem(mnCurPos);
2681 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
2682 mnCurItemId = 0;
2683 mnDownItemId = 0;
2684 mnMouseClicks = 0;
2685 mnMouseModifier = 0;
2686 mnHighItemId = 0;
2691 IMPL_LINK_NOARG(ToolBox, ImplUpdateHdl, Idle *, void)
2694 if( mbFormat && mpData )
2695 ImplFormat();
2698 static void ImplDrawMoreIndicator(vcl::RenderContext& rRenderContext, const Rectangle& rRect, bool bSetColor, bool bRotate )
2700 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
2701 rRenderContext.SetLineColor();
2703 if (bSetColor)
2705 if (rRenderContext.GetSettings().GetStyleSettings().GetFaceColor().IsDark())
2706 rRenderContext.SetFillColor(Color(COL_WHITE));
2707 else
2708 rRenderContext.SetFillColor(Color(COL_BLACK));
2710 float fScaleFactor = rRenderContext.GetDPIScaleFactor();
2712 int linewidth = 1 * fScaleFactor;
2713 int space = 4 * fScaleFactor;
2715 if( !bRotate )
2717 long width = 8 * fScaleFactor;
2718 long height = 5 * fScaleFactor;
2720 //Keep odd b/c drawing code works better
2721 if ( height % 2 == 0 )
2722 height--;
2724 long heightOrig = height;
2726 long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1;
2727 long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1;
2728 while( height >= 1)
2730 rRenderContext.DrawRect( Rectangle( x, y, x + linewidth, y ) );
2731 x += space;
2732 rRenderContext.DrawRect( Rectangle( x, y, x + linewidth, y ) );
2733 x -= space;
2734 y++;
2735 if( height <= heightOrig / 2 + 1) x--;
2736 else x++;
2737 height--;
2740 else
2742 long width = 5 * fScaleFactor;
2743 long height = 8 * fScaleFactor;
2745 //Keep odd b/c drawing code works better
2746 if (width % 2 == 0)
2747 width--;
2749 long widthOrig = width;
2751 long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1;
2752 long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1;
2753 while( width >= 1)
2755 rRenderContext.DrawRect( Rectangle( x, y, x, y + linewidth ) );
2756 y += space;
2757 rRenderContext.DrawRect( Rectangle( x, y, x, y + linewidth ) );
2758 y -= space;
2759 x++;
2760 if( width <= widthOrig / 2 + 1) y--;
2761 else y++;
2762 width--;
2766 rRenderContext.Pop();
2769 static void ImplDrawDropdownArrow(vcl::RenderContext& rRenderContext, const Rectangle& rDropDownRect, bool bSetColor, bool bRotate )
2771 bool bLineColor = rRenderContext.IsLineColor();
2772 bool bFillColor = rRenderContext.IsFillColor();
2773 Color aOldFillColor = rRenderContext.GetFillColor();
2774 Color aOldLineColor = rRenderContext.GetLineColor();
2775 rRenderContext.SetLineColor();
2777 if ( bSetColor )
2779 if (rRenderContext.GetSettings().GetStyleSettings().GetFaceColor().IsDark())
2780 rRenderContext.SetFillColor(Color(COL_WHITE));
2781 else
2782 rRenderContext.SetFillColor(Color(COL_BLACK));
2785 float fScaleFactor = rRenderContext.GetDPIScaleFactor();
2787 if( !bRotate )
2789 long width = 5 * fScaleFactor;
2790 long height = 3 * fScaleFactor;
2792 long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2;
2793 long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2;
2794 while( width >= 1)
2796 rRenderContext.DrawRect( Rectangle( x, y, x+width-1, y ) );
2797 y++;
2798 x++;
2799 width -= 2;
2802 else
2804 long width = 3 * fScaleFactor;
2805 long height = 5 * fScaleFactor;
2807 long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2;
2808 long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2;
2809 while( height >= 1)
2811 rRenderContext.DrawRect( Rectangle( x, y, x, y+height-1 ) );
2812 y++;
2813 x++;
2814 height -= 2;
2818 if( bFillColor )
2819 rRenderContext.SetFillColor(aOldFillColor);
2820 else
2821 rRenderContext.SetFillColor();
2822 if( bLineColor )
2823 rRenderContext.SetLineColor(aOldLineColor);
2824 else
2825 rRenderContext.SetLineColor();
2828 void ToolBox::ImplDrawMenuButton(vcl::RenderContext& rRenderContext, bool bHighlight)
2830 if (!mpData->maMenubuttonItem.maRect.IsEmpty())
2832 // #i53937# paint menu button only if necessary
2833 if (!ImplHasClippedItems())
2834 return;
2836 // execute pending paint requests
2837 ImplCheckUpdate(this);
2839 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
2841 // draw the 'more' indicator / button (>>)
2842 ImplErase(rRenderContext, mpData->maMenubuttonItem.maRect, bHighlight);
2844 if (bHighlight)
2845 ImplDrawButton(rRenderContext, mpData->maMenubuttonItem.maRect, 2, false, true, false );
2847 if (ImplHasClippedItems())
2848 ImplDrawMoreIndicator(rRenderContext, mpData->maMenubuttonItem.maRect, true, !mbHorz);
2850 // store highlight state
2851 mpData->mbMenubuttonSelected = bHighlight;
2853 // restore colors
2854 rRenderContext.Pop();
2858 void ToolBox::ImplDrawSpin(vcl::RenderContext& rRenderContext)
2860 bool bTmpUpper;
2861 bool bTmpLower;
2863 if ( maUpperRect.IsEmpty() || maLowerRect.IsEmpty() )
2864 return;
2866 if ( mnCurLine > 1 )
2867 bTmpUpper = true;
2868 else
2869 bTmpUpper = false;
2871 if ( mnCurLine+mnVisLines-1 < mnCurLines )
2872 bTmpLower = true;
2873 else
2874 bTmpLower = false;
2876 if ( !IsEnabled() )
2878 bTmpUpper = false;
2879 bTmpLower = false;
2882 ImplDrawUpDownButtons(rRenderContext, maUpperRect, maLowerRect,
2883 false/*bUpperIn*/, false/*bLowerIn*/, bTmpUpper, bTmpLower, !mbHorz);
2886 void ToolBox::ImplDrawSeparator(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, const Rectangle& rRect)
2888 if ( nPos >= mpData->m_aItems.size() - 1 )
2889 // no separator if it's the last item
2890 return;
2892 ImplToolItem* pItem = &mpData->m_aItems[nPos];
2893 ImplToolItem* pPreviousItem = &mpData->m_aItems[nPos-1];
2894 ImplToolItem* pNextItem = &mpData->m_aItems[nPos+1];
2896 if ( ( pPreviousItem->mbShowWindow && pNextItem->mbShowWindow ) || pNextItem->mbBreak )
2897 // no separator between two windows or before a break
2898 return;
2900 bool bNativeOk = false;
2901 ControlPart nPart = IsHorizontal() ? ControlPart::SeparatorVert : ControlPart::SeparatorHorz;
2902 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, nPart))
2904 ImplControlValue aControlValue;
2905 ControlState nState = ControlState::NONE;
2906 bNativeOk = rRenderContext.DrawNativeControl(ControlType::Toolbar, nPart, rRect, nState, aControlValue, OUString());
2909 /* Draw the widget only if it can't be drawn natively. */
2910 if (!bNativeOk)
2912 long nCenterPos, nSlim;
2913 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2914 rRenderContext.SetLineColor(rStyleSettings.GetSeparatorColor());
2915 if (IsHorizontal())
2917 nSlim = (pItem->maRect.Bottom() - pItem->maRect.Top ()) / 4;
2918 nCenterPos = pItem->maRect.Center().X();
2919 rRenderContext.DrawLine(Point(nCenterPos, pItem->maRect.Top() + nSlim),
2920 Point(nCenterPos, pItem->maRect.Bottom() - nSlim));
2922 else
2924 nSlim = (pItem->maRect.Right() - pItem->maRect.Left ()) / 4;
2925 nCenterPos = pItem->maRect.Center().Y();
2926 rRenderContext.DrawLine(Point(pItem->maRect.Left() + nSlim, nCenterPos),
2927 Point(pItem->maRect.Right() - nSlim, nCenterPos));
2932 void ToolBox::ImplDrawButton(vcl::RenderContext& rRenderContext, const Rectangle &rRect, sal_uInt16 highlight,
2933 bool bChecked, bool bEnabled, bool bIsWindow )
2935 // draws toolbar button background either native or using a coloured selection
2936 // if bIsWindow is true, the corresponding item is a control and only a selection border will be drawn
2938 bool bNativeOk = false;
2939 if( !bIsWindow && rRenderContext.IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button ) )
2941 ImplControlValue aControlValue;
2942 ControlState nState = ControlState::NONE;
2944 if ( highlight == 1 ) nState |= ControlState::PRESSED;
2945 if ( highlight == 2 ) nState |= ControlState::ROLLOVER;
2946 if ( bEnabled ) nState |= ControlState::ENABLED;
2948 aControlValue.setTristateVal( bChecked ? ButtonValue::On : ButtonValue::Off );
2950 bNativeOk = rRenderContext.DrawNativeControl( ControlType::Toolbar, ControlPart::Button,
2951 rRect, nState, aControlValue, OUString() );
2954 if (!bNativeOk)
2955 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, rRect, bIsWindow ? 3 : highlight,
2956 bChecked, true, bIsWindow, nullptr, 2);
2959 void ToolBox::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, sal_uInt16 nHighlight)
2961 if (nPos >= mpData->m_aItems.size())
2962 return;
2964 // execute pending paint requests
2965 ImplCheckUpdate(this);
2967 ImplDisableFlatButtons();
2969 rRenderContext.SetFillColor();
2971 ImplToolItem* pItem = &mpData->m_aItems[nPos];
2973 if (!pItem->mbEnabled)
2974 nHighlight = 0;
2976 // if the rectangle is outside visible area
2977 if (pItem->maRect.IsEmpty())
2978 return;
2980 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2982 // no gradient background for items that have a popup open
2983 bool bHasOpenPopup = mpFloatWin && (mnDownItemId==pItem->mnId);
2985 bool bHighContrastWhite = false;
2986 // check the face color as highcontrast indicator
2987 // because the toolbox itself might have a gradient
2988 if (rStyleSettings.GetFaceColor() == Color(COL_WHITE))
2989 bHighContrastWhite = true;
2991 // Compute buttons area.
2992 Size aBtnSize = pItem->maRect.GetSize();
2993 if( ImplGetSVData()->maNWFData.mbToolboxDropDownSeparate )
2995 // separate button not for dropdown only where the whole button is painted
2996 // exception: when text position is set to bottom then we want to calculate rect for dropdown only button
2997 if ( ( pItem->mnBits & ToolBoxItemBits::DROPDOWN &&
2998 ((pItem->mnBits & ToolBoxItemBits::DROPDOWNONLY) != ToolBoxItemBits::DROPDOWNONLY) )
2999 || ( ( pItem->mnBits & ToolBoxItemBits::DROPDOWN) && ( meTextPosition == ToolBoxTextPosition::Bottom ) ) )
3001 Rectangle aArrowRect = pItem->GetDropDownRect( mbHorz && ( meTextPosition == ToolBoxTextPosition::Right ) );
3002 if( aArrowRect.Top() == pItem->maRect.Top() ) // dropdown arrow on right side
3003 aBtnSize.Width() -= aArrowRect.GetWidth();
3004 else if ( !( (meTextPosition == ToolBoxTextPosition::Bottom)
3005 && ((pItem->mnBits & ToolBoxItemBits::DROPDOWNONLY) == ToolBoxItemBits::DROPDOWNONLY) ) )
3006 aBtnSize.Height() -= aArrowRect.GetHeight(); // dropdown arrow on bottom side
3010 /* Compute the button/separator rectangle here, we'll need it for
3011 * both the buttons and the separators. */
3012 Rectangle aButtonRect( pItem->maRect.TopLeft(), aBtnSize );
3013 long nOffX = SMALLBUTTON_OFF_NORMAL_X;
3014 long nOffY = SMALLBUTTON_OFF_NORMAL_Y;
3015 long nImageOffX = 0;
3016 long nImageOffY = 0;
3017 DrawButtonFlags nStyle = DrawButtonFlags::NONE;
3019 // draw separators in flat style only
3020 if ( (mnOutStyle & TOOLBOX_STYLE_FLAT) &&
3021 (pItem->meType == ToolBoxItemType::SEPARATOR) &&
3022 nPos > 0
3025 ImplDrawSeparator(rRenderContext, nPos, aButtonRect);
3028 // do nothing if item is no button or will be displayed as window
3029 if ( (pItem->meType != ToolBoxItemType::BUTTON) ||
3030 (pItem->mbShowWindow && !mbCustomizeMode) )
3031 return;
3033 // we need a TBDragMananger to draw the configuration item
3034 ImplTBDragMgr* pMgr;
3035 if ( pItem->mnId == mnConfigItem )
3037 pMgr = ImplGetTBDragMgr();
3038 pMgr->HideDragRect();
3040 else
3041 pMgr = nullptr;
3043 // during configuration mode visible windows will be drawn in a special way
3044 if ( mbCustomizeMode && pItem->mbShowWindow )
3046 vcl::Font aOldFont = rRenderContext.GetFont();
3047 Color aOldTextColor = rRenderContext.GetTextColor();
3049 SetZoomedPointFont(rRenderContext, rStyleSettings.GetAppFont());
3050 rRenderContext.SetLineColor(Color(COL_BLACK));
3051 rRenderContext.SetFillColor(rStyleSettings.GetFieldColor());
3052 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
3053 rRenderContext.DrawRect(pItem->maRect);
3055 Size aSize( GetCtrlTextWidth( pItem->maText ), GetTextHeight() );
3056 Point aPos( pItem->maRect.Left()+2, pItem->maRect.Top() );
3057 aPos.Y() += (pItem->maRect.GetHeight()-aSize.Height())/2;
3058 bool bClip;
3059 if ( (aSize.Width() > pItem->maRect.GetWidth()-2) ||
3060 (aSize.Height() > pItem->maRect.GetHeight()-2) )
3062 bClip = true;
3063 Rectangle aTempRect(pItem->maRect.Left() + 1, pItem->maRect.Top() + 1,
3064 pItem->maRect.Right() - 1, pItem->maRect.Bottom() - 1);
3065 vcl::Region aTempRegion(aTempRect);
3066 rRenderContext.SetClipRegion(aTempRegion);
3068 else
3069 bClip = false;
3070 rRenderContext.DrawCtrlText( aPos, pItem->maText, 0, pItem->maText.getLength() );
3071 if (bClip)
3072 rRenderContext.SetClipRegion();
3073 rRenderContext.SetFont(aOldFont);
3074 rRenderContext.SetTextColor(aOldTextColor);
3076 // draw Config-Frame if required
3077 if (pMgr)
3078 pMgr->UpdateDragRect();
3079 return;
3082 if ( pItem->meState == TRISTATE_TRUE )
3084 nStyle |= DrawButtonFlags::Checked;
3086 else if ( pItem->meState == TRISTATE_INDET )
3088 nStyle |= DrawButtonFlags::DontKnow;
3090 if ( nHighlight == 1 )
3092 nStyle |= DrawButtonFlags::Pressed;
3095 if ( mnOutStyle & TOOLBOX_STYLE_FLAT )
3097 ImplErase(rRenderContext, pItem->maRect, nHighlight != 0, bHasOpenPopup );
3099 else
3101 DecorationView aDecoView(&rRenderContext);
3102 aDecoView.DrawButton(aButtonRect, nStyle);
3105 nOffX += pItem->maRect.Left();
3106 nOffY += pItem->maRect.Top();
3108 // determine what has to be drawn on the button: image, text or both
3109 bool bImage;
3110 bool bText;
3111 ButtonType tmpButtonType = determineButtonType( pItem, meButtonType ); // default to toolbox setting
3112 pItem->DetermineButtonDrawStyle( tmpButtonType, bImage, bText );
3114 // compute output values
3115 long nBtnWidth = aBtnSize.Width()-SMALLBUTTON_HSIZE;
3116 long nBtnHeight = aBtnSize.Height()-SMALLBUTTON_VSIZE;
3117 Size aImageSize;
3118 Size aTxtSize;
3120 if ( bText )
3122 aTxtSize.Width() = GetCtrlTextWidth( pItem->maText );
3123 aTxtSize.Height() = GetTextHeight();
3126 if ( bImage )
3128 const Image* pImage = &(pItem->maImage);
3129 aImageSize = pImage->GetSizePixel();
3131 // determine drawing flags
3132 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
3134 if ( !pItem->mbEnabled || !IsEnabled() )
3135 nImageStyle |= DrawImageFlags::Disable;
3137 // #i35563# the dontknow state indicates different states at the same time
3138 // which should not be rendered disabled but normal
3140 // draw the image
3141 nImageOffX = nOffX;
3142 nImageOffY = nOffY;
3143 if ( ( (pItem->mnBits & (ToolBoxItemBits::LEFT|ToolBoxItemBits::DROPDOWN)) || bText )
3144 && ( meTextPosition == ToolBoxTextPosition::Right ) )
3146 // left align also to leave space for drop down arrow
3147 // and when drawing text+image
3148 // just center in y, except for vertical (ie rotated text)
3149 if( mbHorz || !bText )
3150 nImageOffY += (nBtnHeight-aImageSize.Height())/2;
3152 else
3154 nImageOffX += (nBtnWidth-aImageSize.Width())/2;
3155 if ( meTextPosition == ToolBoxTextPosition::Right )
3156 nImageOffY += (nBtnHeight-aImageSize.Height())/2;
3158 if ( nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) )
3160 if( bHasOpenPopup )
3161 ImplDrawFloatwinBorder(rRenderContext, pItem);
3162 else
3163 ImplDrawButton(rRenderContext, aButtonRect, nHighlight, pItem->meState == TRISTATE_TRUE,
3164 pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow);
3166 if( nHighlight != 0 )
3168 if( bHighContrastWhite )
3169 nImageStyle |= DrawImageFlags::ColorTransform;
3172 rRenderContext.DrawImage(Point( nImageOffX, nImageOffY ), *pImage, nImageStyle);
3175 // draw the text
3176 bool bRotate = false;
3177 if ( bText )
3179 long nTextOffX = nOffX;
3180 long nTextOffY = nOffY;
3182 // rotate text when vertically docked
3183 vcl::Font aOldFont = rRenderContext.GetFont();
3184 if( pItem->mbVisibleText && !ImplIsFloatingMode() &&
3185 ((meAlign == WindowAlign::Left) || (meAlign == WindowAlign::Right)) )
3187 bRotate = true;
3189 vcl::Font aRotateFont = aOldFont;
3190 aRotateFont.SetOrientation( 2700 );
3192 // center horizontally
3193 nTextOffX += aTxtSize.Height();
3194 nTextOffX += (nBtnWidth-aTxtSize.Height())/2;
3196 // add in image offset
3197 if( bImage )
3198 nTextOffY = nImageOffY + aImageSize.Height() + TB_IMAGETEXTOFFSET;
3200 rRenderContext.SetFont(aRotateFont);
3202 else
3204 if ( meTextPosition == ToolBoxTextPosition::Right )
3206 // center vertically
3207 nTextOffY += (nBtnHeight-aTxtSize.Height())/2;
3209 // add in image offset
3210 if( bImage )
3211 nTextOffX = nImageOffX + aImageSize.Width() + TB_IMAGETEXTOFFSET;
3213 else
3215 long nArrowHeight = ( pItem->mnBits & ToolBoxItemBits::DROPDOWN )
3216 ? TB_DROPDOWNARROWWIDTH : 0;
3218 // only if buton is a "dropdown only" type then is painted as a single button
3219 // and we need to move text above the arrow
3220 if ( ImplGetSVData()->maNWFData.mbToolboxDropDownSeparate
3221 && (pItem->mnBits & ToolBoxItemBits::DROPDOWNONLY) != ToolBoxItemBits::DROPDOWNONLY )
3222 nArrowHeight = 0;
3224 nTextOffY += nBtnHeight - aTxtSize.Height() - nArrowHeight;
3228 // draw selection only if not already drawn during image output (see above)
3229 if ( !bImage && (nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) ) )
3231 if( bHasOpenPopup )
3232 ImplDrawFloatwinBorder(rRenderContext, pItem);
3233 else
3234 ImplDrawButton(rRenderContext, pItem->maRect, nHighlight, pItem->meState == TRISTATE_TRUE,
3235 pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow );
3238 DrawTextFlags nTextStyle = DrawTextFlags::NONE;
3239 if ( !pItem->mbEnabled )
3240 nTextStyle |= DrawTextFlags::Disable;
3241 rRenderContext.DrawCtrlText( Point( nTextOffX, nTextOffY ), pItem->maText,
3242 0, pItem->maText.getLength(), nTextStyle );
3243 if ( bRotate )
3244 SetFont( aOldFont );
3247 // paint optional drop down arrow
3248 if ( pItem->mnBits & ToolBoxItemBits::DROPDOWN )
3250 Rectangle aDropDownRect( pItem->GetDropDownRect( mbHorz && ( meTextPosition == ToolBoxTextPosition::Right ) ) );
3251 bool bSetColor = true;
3252 if ( !pItem->mbEnabled || !IsEnabled() )
3254 bSetColor = false;
3255 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
3258 // dropdown only will be painted without inner border
3259 if( (pItem->mnBits & ToolBoxItemBits::DROPDOWNONLY) != ToolBoxItemBits::DROPDOWNONLY )
3261 ImplErase(rRenderContext, aDropDownRect, nHighlight != 0, bHasOpenPopup);
3263 if( nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) )
3265 if( bHasOpenPopup )
3266 ImplDrawFloatwinBorder(rRenderContext, pItem);
3267 else
3268 ImplDrawButton(rRenderContext, aDropDownRect, nHighlight, pItem->meState == TRISTATE_TRUE,
3269 pItem->mbEnabled && IsEnabled(), false);
3272 ImplDrawDropdownArrow(rRenderContext, aDropDownRect, bSetColor, bRotate);
3275 // draw config-frame if required
3276 if (pMgr)
3277 pMgr->UpdateDragRect();
3280 void ToolBox::ImplDrawFloatwinBorder(vcl::RenderContext& rRenderContext, ImplToolItem* pItem)
3282 if ( !pItem->maRect.IsEmpty() )
3284 Rectangle aRect( mpFloatWin->ImplGetItemEdgeClipRect() );
3285 aRect.SetPos( AbsoluteScreenToOutputPixel( aRect.TopLeft() ) );
3286 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
3287 Point p1, p2;
3289 p1 = pItem->maRect.TopLeft();
3290 p1.X()++;
3291 p2 = pItem->maRect.TopRight();
3292 p2.X()--;
3293 rRenderContext.DrawLine( p1, p2);
3294 p1 = pItem->maRect.BottomLeft();
3295 p1.X()++;
3296 p2 = pItem->maRect.BottomRight();
3297 p2.X()--;
3298 rRenderContext.DrawLine( p1, p2);
3300 p1 = pItem->maRect.TopLeft();
3301 p1.Y()++;
3302 p2 = pItem->maRect.BottomLeft();
3303 p2.Y()--;
3304 rRenderContext.DrawLine( p1, p2);
3305 p1 = pItem->maRect.TopRight();
3306 p1.Y()++;
3307 p2 = pItem->maRect.BottomRight();
3308 p2.Y()--;
3309 rRenderContext.DrawLine( p1, p2);
3313 void ToolBox::ImplFloatControl( bool bStart, FloatingWindow* pFloatWindow )
3316 if ( bStart )
3318 mpFloatWin = pFloatWindow;
3320 // redraw item, to trigger drawing of a special border
3321 InvalidateItem(mnCurPos);
3323 mbDrag = false;
3324 EndTracking();
3325 if (IsMouseCaptured())
3326 ReleaseMouse();
3328 else
3330 mpFloatWin = nullptr;
3332 // if focus is still in this toolbox, then the floater was opened by keyboard
3333 // draw current item with highlight and keep old state
3334 bool bWasKeyboardActivate = mpData->mbDropDownByKeyboard;
3336 if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
3337 InvalidateItem(mnCurPos);
3338 Deactivate();
3340 if( !bWasKeyboardActivate )
3342 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
3343 mnCurItemId = 0;
3344 mnHighItemId = 0;
3346 mnDownItemId = 0;
3351 void ToolBox::ShowLine( bool bNext )
3354 mbFormat = true;
3356 if ( mpData->mbPageScroll )
3358 sal_uInt16 delta = mnVisLines;
3359 if ( bNext )
3361 mnCurLine = mnCurLine + delta;
3362 if ( mnCurLine+mnVisLines-1 > mnCurLines )
3363 mnCurLine = mnCurLines - mnVisLines+1;
3365 else
3367 if( mnCurLine >= delta+1 )
3368 mnCurLine = mnCurLine - delta;
3369 else
3370 mnCurLine = 1;
3373 else
3375 if ( bNext )
3376 mnCurLine++;
3377 else
3378 mnCurLine--;
3381 ImplFormat();
3384 bool ToolBox::ImplHandleMouseMove( const MouseEvent& rMEvt, bool bRepeat )
3386 Point aMousePos = rMEvt.GetPosPixel();
3388 if ( !mpData )
3389 return false;
3391 // ToolBox active?
3392 if ( mbDrag && mnCurPos != TOOLBOX_ITEM_NOTFOUND )
3394 // is the cursor over the item?
3395 ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
3396 if ( pItem->maRect.IsInside( aMousePos ) )
3398 if ( !mnCurItemId )
3400 InvalidateItem(mnCurPos);
3401 mnCurItemId = pItem->mnId;
3402 Highlight();
3405 if ( (pItem->mnBits & ToolBoxItemBits::REPEAT) && bRepeat )
3406 Select();
3408 else
3410 if ( mnCurItemId )
3412 InvalidateItem(mnCurPos);
3413 mnCurItemId = 0;
3414 InvalidateItem(mnCurPos);
3415 Highlight();
3419 return true;
3422 if ( mbUpper )
3424 bool bNewIn = maUpperRect.IsInside( aMousePos );
3425 if ( bNewIn != mbIn )
3427 mbIn = bNewIn;
3428 InvalidateSpin(true, false);
3430 return true;
3433 if ( mbLower )
3435 bool bNewIn = maLowerRect.IsInside( aMousePos );
3436 if ( bNewIn != mbIn )
3438 mbIn = bNewIn;
3439 InvalidateSpin(false);
3441 return true;
3444 return false;
3447 bool ToolBox::ImplHandleMouseButtonUp( const MouseEvent& rMEvt, bool bCancel )
3449 ImplDisableFlatButtons();
3451 if ( !mpData )
3452 return false;
3454 // stop eventual running dropdown timer
3455 if( mnCurPos < mpData->m_aItems.size() &&
3456 (mpData->m_aItems[mnCurPos].mnBits & ToolBoxItemBits::DROPDOWN ) )
3458 mpData->maDropdownTimer.Stop();
3461 if ( mbDrag || mbSelection )
3463 // set mouse data if in selection mode, as then
3464 // the MouseButtonDown handler cannot be called
3465 if ( mbSelection )
3467 mnMouseClicks = rMEvt.GetClicks();
3468 mnMouseModifier = rMEvt.GetModifier();
3471 Deactivate();
3473 if ( mbDrag )
3474 mbDrag = false;
3475 else
3477 mbSelection = false;
3478 if ( mnCurPos == TOOLBOX_ITEM_NOTFOUND )
3479 return true;
3482 // has mouse been released on top of item?
3483 if( mnCurPos < mpData->m_aItems.size() )
3485 ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
3486 if ( pItem->maRect.IsInside( rMEvt.GetPosPixel() ) )
3488 mnCurItemId = pItem->mnId;
3489 if ( !bCancel )
3491 // execute AutoCheck if required
3492 if ( pItem->mnBits & ToolBoxItemBits::AUTOCHECK )
3494 if ( pItem->mnBits & ToolBoxItemBits::RADIOCHECK )
3496 if ( pItem->meState != TRISTATE_TRUE )
3497 SetItemState( pItem->mnId, TRISTATE_TRUE );
3499 else
3501 if ( pItem->meState != TRISTATE_TRUE )
3502 pItem->meState = TRISTATE_TRUE;
3503 else
3504 pItem->meState = TRISTATE_FALSE;
3508 // do not call Select when Repeat is active, as in this
3509 // case that was triggered already in MouseButtonDown
3510 if ( !(pItem->mnBits & ToolBoxItemBits::REPEAT) )
3512 // prevent from being destroyed in the select handler
3513 VclPtr<vcl::Window> xWindow = this;
3514 Select();
3515 if ( xWindow->IsDisposed() )
3516 return true;
3523 // Items not destroyed, in Select handler
3524 if ( mnCurItemId )
3526 // Get current pos for the case that items are inserted/removed
3527 // in the toolBox
3528 mnCurPos = GetItemPos( mnCurItemId );
3529 if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
3531 InvalidateItem(mnCurPos);
3532 Flush();
3538 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
3539 mnCurItemId = 0;
3540 mnDownItemId = 0;
3541 mnMouseClicks = 0;
3542 mnMouseModifier = 0;
3543 return true;
3545 else if ( mbUpper || mbLower )
3547 if ( mbIn )
3548 ShowLine( !mbUpper );
3549 mbUpper = false;
3550 mbLower = false;
3551 mbIn = false;
3552 InvalidateSpin();
3553 return true;
3556 return false;
3559 void ToolBox::MouseMove( const MouseEvent& rMEvt )
3561 // pressing a modifier generates synthetic mouse moves
3562 // ignore it if keyboard selection is active
3563 if( HasFocus() && ( rMEvt.GetMode() & MouseEventModifiers::MODIFIERCHANGED ) )
3564 return;
3566 if ( ImplHandleMouseMove( rMEvt ) )
3567 return;
3569 ImplDisableFlatButtons();
3571 Point aMousePos = rMEvt.GetPosPixel();
3573 // only highlight when the focus is not inside a child window of a toolbox
3574 // eg, in a edit control
3575 // and do not highlight when focus is in a different toolbox
3576 bool bDrawHotSpot = true;
3577 vcl::Window *pWin = Application::GetFocusWindow();
3578 if( pWin && pWin->ImplGetWindowImpl()->mbToolBox && pWin != this )
3579 bDrawHotSpot = false;
3581 if ( mbSelection && bDrawHotSpot )
3583 sal_uInt16 i = 0;
3584 sal_uInt16 nNewPos = TOOLBOX_ITEM_NOTFOUND;
3586 // search the item that has been clicked
3587 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
3588 while ( it != mpData->m_aItems.end() )
3590 // if the mouse position is in this item,
3591 // we can stop the search
3592 if ( it->maRect.IsInside( aMousePos ) )
3594 // select it if it is a button
3595 if ( it->meType == ToolBoxItemType::BUTTON )
3597 // if button is disabled, do not
3598 // change it
3599 if ( !it->mbEnabled || it->mbShowWindow )
3600 nNewPos = mnCurPos;
3601 else
3602 nNewPos = i;
3605 break;
3608 i++;
3609 ++it;
3612 // was a new entry selected?
3613 // don't change selection if keyboard selection is active and
3614 // mouse leaves the toolbox
3615 if ( nNewPos != mnCurPos && !( HasFocus() && nNewPos == TOOLBOX_ITEM_NOTFOUND ) )
3617 if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
3619 InvalidateItem(mnCurPos);
3620 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( mnCurPos ) );
3623 mnCurPos = nNewPos;
3624 if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND )
3626 mnCurItemId = mnHighItemId = it->mnId;
3627 InvalidateItem(mnCurPos);
3629 else
3630 mnCurItemId = mnHighItemId = 0;
3632 Highlight();
3634 return;
3637 if ( mbDragging )
3639 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3640 pMgr->Dragging( aMousePos );
3641 return;
3644 PointerStyle eStyle = PointerStyle::Arrow;
3646 // change mouse cursor over drag area
3647 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
3648 if( pWrapper && pWrapper->GetDragArea().IsInside( rMEvt.GetPosPixel() ) )
3649 eStyle = PointerStyle::Move;
3651 if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING )
3653 if ( rMEvt.GetMode() & MouseEventModifiers::SIMPLEMOVE )
3655 sal_uInt16 nLinePtr = ImplTestLineSize( this, rMEvt.GetPosPixel() );
3656 if ( nLinePtr & DOCK_LINEHSIZE )
3658 if ( meAlign == WindowAlign::Left )
3659 eStyle = PointerStyle::WindowESize;
3660 else
3661 eStyle = PointerStyle::WindowWSize;
3663 else if ( nLinePtr & DOCK_LINEVSIZE )
3665 if ( meAlign == WindowAlign::Top )
3666 eStyle = PointerStyle::WindowSSize;
3667 else
3668 eStyle = PointerStyle::WindowNSize;
3673 if ( (eStyle == PointerStyle::Arrow) && mbCustomizeMode )
3675 // search the item which was clicked
3676 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
3677 while ( it != mpData->m_aItems.end() )
3679 // show resize pointer if it is a customize window
3680 if ( it->mbShowWindow )
3682 if ( it->maRect.IsInside( aMousePos ) )
3684 if ( it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X() )
3685 eStyle = PointerStyle::HSizeBar;
3686 break;
3690 ++it;
3694 if ( bDrawHotSpot && ( (mnOutStyle & TOOLBOX_STYLE_FLAT) || !mnOutStyle ) )
3696 bool bClearHigh = true;
3697 if ( !rMEvt.IsLeaveWindow() && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
3699 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
3700 while ( it != mpData->m_aItems.end() )
3702 if ( it->maRect.IsInside( aMousePos ) )
3704 if ( (it->meType == ToolBoxItemType::BUTTON) && it->mbEnabled )
3706 if ( !mnOutStyle || (mnOutStyle & TOOLBOX_STYLE_FLAT) )
3708 bClearHigh = false;
3709 if ( mnHighItemId != it->mnId )
3711 sal_uInt16 nTempPos = sal::static_int_cast<sal_uInt16>(it - mpData->m_aItems.begin());
3712 if ( mnHighItemId )
3714 ImplHideFocus();
3715 sal_uInt16 nPos = GetItemPos( mnHighItemId );
3716 InvalidateItem(nPos);
3717 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) );
3719 if ( mpData->mbMenubuttonSelected )
3721 // remove highlight from menubutton
3722 InvalidateMenuButton();
3724 mnHighItemId = it->mnId;
3725 InvalidateItem(nTempPos);
3726 ImplShowFocus();
3727 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT );
3731 break;
3734 ++it;
3738 // only clear highlight when focus is not in toolbar
3739 bool bMenuButtonHit = mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) && ImplHasClippedItems();
3740 if ( bClearHigh || bMenuButtonHit )
3742 if ( !bMenuButtonHit && mpData->mbMenubuttonSelected )
3744 // remove highlight from menubutton
3745 InvalidateMenuButton();
3748 if( mnHighItemId )
3750 sal_uInt16 nClearPos = GetItemPos( mnHighItemId );
3751 if ( nClearPos != TOOLBOX_ITEM_NOTFOUND )
3753 InvalidateItem(nClearPos);
3754 if( nClearPos != mnCurPos )
3755 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nClearPos ) );
3757 ImplHideFocus();
3758 mnHighItemId = 0;
3761 if( bMenuButtonHit )
3763 InvalidateMenuButton();
3768 if ( meLastStyle != eStyle )
3770 meLastStyle = eStyle;
3771 Pointer aPtr( eStyle );
3772 SetPointer( aPtr );
3775 DockingWindow::MouseMove( rMEvt );
3778 void ToolBox::MouseButtonDown( const MouseEvent& rMEvt )
3780 // only trigger toolbox for left mouse button and when
3781 // we're not in normal operation
3782 if ( rMEvt.IsLeft() && !mbDrag && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
3784 // call activate already here, as items could
3785 // be exchanged
3786 Activate();
3788 // update ToolBox here, such that user knows it
3789 if ( mbFormat )
3791 ImplFormat();
3792 Update();
3795 Point aMousePos = rMEvt.GetPosPixel();
3796 sal_uInt16 i = 0;
3797 sal_uInt16 nNewPos = TOOLBOX_ITEM_NOTFOUND;
3799 // search for item that was clicked
3800 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
3801 while ( it != mpData->m_aItems.end() )
3803 // is this the item?
3804 if ( it->maRect.IsInside( aMousePos ) )
3806 // do nothing if it is a separator or
3807 // if the item has been disabled
3808 if ( (it->meType == ToolBoxItemType::BUTTON) &&
3809 (!it->mbShowWindow || mbCustomizeMode) )
3810 nNewPos = i;
3812 break;
3815 i++;
3816 ++it;
3819 // item found
3820 if ( nNewPos != TOOLBOX_ITEM_NOTFOUND )
3822 if ( mbCustomize )
3824 if ( rMEvt.IsMod2() || mbCustomizeMode )
3826 Deactivate();
3828 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3829 Rectangle aItemRect = GetItemRect( it->mnId );
3830 mnConfigItem = it->mnId;
3832 bool bResizeItem;
3833 if ( mbCustomizeMode && it->mbShowWindow &&
3834 (it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X()) )
3835 bResizeItem = true;
3836 else
3837 bResizeItem = false;
3838 pMgr->StartDragging( this, aMousePos, aItemRect, 0, bResizeItem );
3839 return;
3843 if ( !it->mbEnabled )
3845 Deactivate();
3846 return;
3849 // update actual data
3850 StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
3851 mnCurPos = i;
3852 mnCurItemId = it->mnId;
3853 mnDownItemId = mnCurItemId;
3854 mnMouseClicks = rMEvt.GetClicks();
3855 mnMouseModifier = rMEvt.GetModifier();
3856 if ( it->mnBits & ToolBoxItemBits::REPEAT )
3857 nTrackFlags |= StartTrackingFlags::ButtonRepeat;
3859 if ( mbSelection )
3861 InvalidateItem(mnCurPos);
3862 Highlight();
3864 else
3866 // update bDrag here, as it is evaluated in the EndSelection
3867 mbDrag = true;
3869 // on double-click: only call the handler, but do so before the button
3870 // is hit, as in the handler dragging
3871 // can be terminated
3872 if ( rMEvt.GetClicks() == 2 )
3873 DoubleClick();
3875 if ( mbDrag )
3877 InvalidateItem(mnCurPos);
3878 Highlight();
3881 // was dropdown arrow pressed
3882 if( (it->mnBits & ToolBoxItemBits::DROPDOWN) )
3884 if( ( (it->mnBits & ToolBoxItemBits::DROPDOWNONLY) == ToolBoxItemBits::DROPDOWNONLY)
3885 || it->GetDropDownRect( mbHorz && ( meTextPosition == ToolBoxTextPosition::Right ) ).IsInside( aMousePos ))
3887 // dropdownonly always triggers the dropdown handler, over the whole button area
3889 // the drop down arrow should not trigger the item action
3890 mpData->mbDropDownByKeyboard = false;
3891 mpData->maDropdownClickHdl.Call( this );
3893 // do not reset data if the dropdown handler opened a floating window
3894 // see ImplFloatControl()
3895 if( !mpFloatWin )
3897 // no floater was opened
3898 Deactivate();
3899 InvalidateItem(mnCurPos);
3901 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
3902 mnCurItemId = 0;
3903 mnDownItemId = 0;
3904 mnMouseClicks = 0;
3905 mnMouseModifier = 0;
3906 mnHighItemId = 0;
3908 return;
3910 else // activate long click timer
3911 mpData->maDropdownTimer.Start();
3914 // call Click handler
3915 if ( rMEvt.GetClicks() != 2 )
3916 Click();
3918 // also call Select handler at repeat
3919 if ( nTrackFlags & StartTrackingFlags::ButtonRepeat )
3920 Select();
3922 // if the actions was not aborted in Click handler
3923 if ( mbDrag )
3924 StartTracking( nTrackFlags );
3927 // if mouse was clicked over an item we
3928 // can abort here
3929 return;
3932 Deactivate();
3934 // menu button hit ?
3935 if( mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) && ImplHasClippedItems() )
3937 ExecuteCustomMenu();
3938 return;
3941 // check scroll- and next-buttons here
3942 if ( maUpperRect.IsInside( aMousePos ) )
3944 if ( mnCurLine > 1 )
3946 StartTracking();
3947 mbUpper = true;
3948 mbIn = true;
3949 InvalidateSpin(true, false);
3951 return;
3953 if ( maLowerRect.IsInside( aMousePos ) )
3955 if ( mnCurLine+mnVisLines-1 < mnCurLines )
3957 StartTracking();
3958 mbLower = true;
3959 mbIn = true;
3960 InvalidateSpin(false);
3962 return;
3965 // Linesizing testen
3966 if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING )
3968 sal_uInt16 nLineMode = ImplTestLineSize( this, aMousePos );
3969 if ( nLineMode )
3971 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3973 // call handler, such that we can set the
3974 // dock rectangles
3975 StartDocking();
3977 Point aPos = GetParent()->OutputToScreenPixel( GetPosPixel() );
3978 Size aSize = GetSizePixel();
3979 aPos = ScreenToOutputPixel( aPos );
3981 // start dragging
3982 pMgr->StartDragging( this, aMousePos, Rectangle( aPos, aSize ),
3983 nLineMode, false );
3984 return;
3988 // no item, then only click or double click
3989 if ( rMEvt.GetClicks() == 2 )
3990 DoubleClick();
3991 else
3992 Click();
3995 if ( !mbDrag && !mbSelection && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
3996 DockingWindow::MouseButtonDown( rMEvt );
3999 void ToolBox::MouseButtonUp( const MouseEvent& rMEvt )
4001 if ( ImplHandleMouseButtonUp( rMEvt ) )
4002 return;
4004 if ( mbDragging && (rMEvt.IsLeft() || mbCommandDrag) )
4006 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
4007 pMgr->EndDragging();
4008 return;
4010 mbCommandDrag = false;
4012 DockingWindow::MouseButtonUp( rMEvt );
4015 void ToolBox::Tracking( const TrackingEvent& rTEvt )
4017 VclPtr<vcl::Window> xWindow = this;
4019 if ( rTEvt.IsTrackingEnded() )
4020 ImplHandleMouseButtonUp( rTEvt.GetMouseEvent(), rTEvt.IsTrackingCanceled() );
4021 else
4022 ImplHandleMouseMove( rTEvt.GetMouseEvent(), rTEvt.IsTrackingRepeat() );
4024 if ( xWindow->IsDisposed() )
4025 // toolbox was deleted
4026 return;
4027 DockingWindow::Tracking( rTEvt );
4030 void ToolBox::InvalidateItem(sal_uInt16 nPosition)
4032 if (mpData && nPosition < mpData->m_aItems.size())
4034 ImplToolItem* pItem = &mpData->m_aItems[nPosition];
4035 Invalidate(pItem->maRect);
4039 void ToolBox::InvalidateMenuButton()
4041 if (!mpData->maMenubuttonItem.maRect.IsEmpty())
4042 Invalidate(mpData->maMenubuttonItem.maRect);
4045 void ToolBox::InvalidateSpin(bool bUpperIn, bool bLowerIn)
4047 if (bUpperIn && !maUpperRect.IsEmpty())
4048 Invalidate(maUpperRect);
4050 if (bLowerIn && !maLowerRect.IsEmpty())
4051 Invalidate(maLowerRect);
4054 void ToolBox::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rPaintRect)
4056 if( mpData->mbIsPaintLocked )
4057 return;
4059 if (rPaintRect == Rectangle(0, 0, mnDX-1, mnDY-1))
4060 mbFullPaint = true;
4061 ImplFormat();
4062 mbFullPaint = false;
4064 ImplDrawBackground(rRenderContext, rPaintRect);
4066 if ( (mnWinStyle & WB_BORDER) && !ImplIsFloatingMode() )
4067 ImplDrawBorder(rRenderContext);
4069 if( !ImplIsFloatingMode() )
4070 ImplDrawGrip(rRenderContext);
4072 ImplDrawMenuButton(rRenderContext, mpData->mbMenubuttonSelected);
4074 // draw SpinButtons
4075 if (mnWinStyle & WB_SCROLL)
4077 if (mnCurLines > mnLines)
4078 ImplDrawSpin(rRenderContext);
4081 // draw buttons
4082 sal_uInt16 nHighPos;
4083 if ( mnHighItemId )
4084 nHighPos = GetItemPos( mnHighItemId );
4085 else
4086 nHighPos = TOOLBOX_ITEM_NOTFOUND;
4088 sal_uInt16 nCount = (sal_uInt16)mpData->m_aItems.size();
4089 for( sal_uInt16 i = 0; i < nCount; i++ )
4091 ImplToolItem* pItem = &mpData->m_aItems[i];
4093 // only draw when the rectangle is in the draw rectangle
4094 if ( !pItem->maRect.IsEmpty() && rPaintRect.IsOver( pItem->maRect ) )
4096 sal_uInt16 nHighlight = 0;
4097 if ( i == mnCurPos )
4098 nHighlight = 1;
4099 else if ( i == nHighPos )
4100 nHighlight = 2;
4101 ImplDrawItem(rRenderContext, i, nHighlight);
4104 ImplShowFocus();
4107 void ToolBox::Resize()
4109 Size aSize = GetOutputSizePixel();
4110 // #i31422# some WindowManagers send (0,0) sizes when
4111 // switching virtual desktops - ignore this and avoid reformatting
4112 if( !aSize.Width() && !aSize.Height() )
4113 return;
4115 long nOldDX = mnDX;
4116 long nOldDY = mnDY;
4117 mnDX = aSize.Width();
4118 mnDY = aSize.Height();
4120 mnLastResizeDY = 0;
4122 // invalidate everything to have gradient backgrounds properly drawn
4123 Invalidate();
4125 // If we have any expandable entries, then force a reformat first using
4126 // their optimal sizes, then share out the excess space evenly across those
4127 // expandables and reformat again
4128 std::vector<size_t> aExpandables;
4129 for (size_t i = 0; i < mpData->m_aItems.size(); ++i)
4131 if (mpData->m_aItems[i].mbExpand)
4133 vcl::Window *pWindow = mpData->m_aItems[i].mpWindow;
4134 SAL_INFO_IF(!pWindow, "vcl.layout", "only tabitems with window supported at the moment");
4135 if (!pWindow)
4136 continue;
4137 Size aWinSize(pWindow->GetSizePixel());
4138 Size aPrefSize(pWindow->get_preferred_size());
4139 aWinSize.Width() = aPrefSize.Width();
4140 pWindow->SetSizePixel(aWinSize);
4141 aExpandables.push_back(i);
4145 // re-format or re-draw
4146 if ( mbScroll || !aExpandables.empty() )
4148 if ( !mbFormat || !aExpandables.empty() )
4150 mbFormat = true;
4151 if( IsReallyVisible() || !aExpandables.empty() )
4153 ImplFormat(true);
4155 if (!aExpandables.empty())
4157 //Get how big the optimal size is
4158 Rectangle aBounds;
4159 for (const ImplToolItem & rItem : mpData->m_aItems)
4161 aBounds.Union( rItem.maRect );
4164 long nOptimalWidth = aBounds.GetWidth();
4165 long nDiff = aSize.Width() - nOptimalWidth;
4166 nDiff /= aExpandables.size();
4168 //share out the diff from optimal to real across
4169 //expandable entries
4170 for (size_t nIndex : aExpandables)
4172 vcl::Window *pWindow = mpData->m_aItems[nIndex].mpWindow;
4173 Size aWinSize(pWindow->GetSizePixel());
4174 Size aPrefSize(pWindow->get_preferred_size());
4175 aWinSize.Width() = aPrefSize.Width() + nDiff;
4176 pWindow->SetSizePixel(aWinSize);
4179 //now reformat with final sizes
4180 mbFormat = true;
4181 ImplFormat(true);
4187 // redraw border
4188 if ( mnWinStyle & WB_BORDER )
4190 // as otherwise, when painting we might think we have to re-draw everything
4191 if ( mbFormat && IsReallyVisible() )
4192 Invalidate();
4193 else
4195 if ( mnRightBorder )
4197 if ( nOldDX > mnDX )
4198 Invalidate( Rectangle( mnDX-mnRightBorder-1, 0, mnDX, mnDY ) );
4199 else
4200 Invalidate( Rectangle( nOldDX-mnRightBorder-1, 0, nOldDX, nOldDY ) );
4203 if ( mnBottomBorder )
4205 if ( nOldDY > mnDY )
4206 Invalidate( Rectangle( 0, mnDY-mnBottomBorder-1, mnDX, mnDY ) );
4207 else
4208 Invalidate( Rectangle( 0, nOldDY-mnBottomBorder-1, nOldDX, nOldDY ) );
4214 const OUString& ToolBox::ImplGetHelpText( sal_uInt16 nItemId ) const
4216 ImplToolItem* pItem = ImplGetItem( nItemId );
4218 assert( pItem );
4220 if ( pItem->maHelpText.isEmpty() && ( !pItem->maHelpId.isEmpty() || pItem->maCommandStr.getLength() ))
4222 Help* pHelp = Application::GetHelp();
4223 if ( pHelp )
4225 if ( pItem->maCommandStr.getLength() )
4226 pItem->maHelpText = pHelp->GetHelpText( pItem->maCommandStr, this );
4227 if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() )
4228 pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
4232 return pItem->maHelpText;
4235 void ToolBox::RequestHelp( const HelpEvent& rHEvt )
4237 sal_uInt16 nItemId;
4238 Point aHelpPos;
4240 if( !rHEvt.KeyboardActivated() )
4242 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
4243 aHelpPos = rHEvt.GetMousePosPixel();
4245 else
4247 if( !mnHighItemId )
4248 return;
4249 else
4250 nItemId = mnHighItemId;
4251 Rectangle aRect( GetItemRect( nItemId ) );
4252 if( aRect.IsEmpty() )
4253 return;
4254 else
4255 aHelpPos = OutputToScreenPixel( aRect.Center() );
4258 if ( nItemId )
4260 if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) )
4262 // get rectangle
4263 Rectangle aTempRect = GetItemRect( nItemId );
4264 Point aPt = OutputToScreenPixel( aTempRect.TopLeft() );
4265 aTempRect.Left() = aPt.X();
4266 aTempRect.Top() = aPt.Y();
4267 aPt = OutputToScreenPixel( aTempRect.BottomRight() );
4268 aTempRect.Right() = aPt.X();
4269 aTempRect.Bottom() = aPt.Y();
4271 // get text and display it
4272 OUString aStr = GetQuickHelpText( nItemId );
4273 const OUString& rHelpStr = GetHelpText( nItemId );
4274 if (aStr.isEmpty())
4275 aStr = MnemonicGenerator::EraseAllMnemonicChars( GetItemText( nItemId ) );
4276 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
4278 if (!rHelpStr.isEmpty())
4279 aStr = rHelpStr;
4280 Help::ShowBalloon( this, aHelpPos, aTempRect, aStr );
4282 else
4283 Help::ShowQuickHelp( this, aTempRect, aStr, rHelpStr, QuickHelpFlags::CtrlText );
4284 return;
4286 else if ( rHEvt.GetMode() & HelpEventMode::EXTENDED )
4288 OUString aCommand = GetItemCommand( nItemId );
4289 OString aHelpId( GetHelpId( nItemId ) );
4291 if ( !aCommand.isEmpty() || !aHelpId.isEmpty() )
4293 // If help is available then trigger it
4294 Help* pHelp = Application::GetHelp();
4295 if ( pHelp )
4297 if ( !aCommand.isEmpty() )
4298 pHelp->Start( aCommand, this );
4299 else if ( !aHelpId.isEmpty() )
4300 pHelp->Start( OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), this );
4302 return;
4307 DockingWindow::RequestHelp( rHEvt );
4310 bool ToolBox::EventNotify( NotifyEvent& rNEvt )
4312 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
4314 KeyEvent aKEvt = *rNEvt.GetKeyEvent();
4315 vcl::KeyCode aKeyCode = aKEvt.GetKeyCode();
4316 sal_uInt16 nKeyCode = aKeyCode.GetCode();
4317 switch( nKeyCode )
4319 case KEY_TAB:
4321 // internal TAB cycling only if parent is not a dialog or if we are the only child
4322 // otherwise the dialog control will take over
4323 vcl::Window *pParent = ImplGetParent();
4324 bool bOldSchoolContainer =
4325 ((pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL &&
4326 pParent->GetChildCount() != 1);
4327 bool bNoTabCycling = bOldSchoolContainer || isContainerWindow(pParent);
4329 if( bNoTabCycling && ! (GetStyle() & WB_FORCETABCYCLE) )
4330 return DockingWindow::EventNotify( rNEvt );
4331 else if( ImplChangeHighlightUpDn( aKeyCode.IsShift() , bNoTabCycling ) )
4332 return false;
4333 else
4334 return DockingWindow::EventNotify( rNEvt );
4336 default:
4337 break;
4340 else if( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
4342 if( rNEvt.GetWindow() == this )
4344 // the toolbar itself got the focus
4345 if( mnLastFocusItemId != 0 )
4347 // restore last item
4348 ImplChangeHighlight( ImplGetItem( mnLastFocusItemId ) );
4349 mnLastFocusItemId = 0;
4351 else if( (GetGetFocusFlags() & (GetFocusFlags::Backward|GetFocusFlags::Tab) ) == (GetFocusFlags::Backward|GetFocusFlags::Tab))
4352 // Shift-TAB was pressed in the parent
4353 ImplChangeHighlightUpDn( false );
4354 else
4355 ImplChangeHighlightUpDn( true );
4357 mnLastFocusItemId = 0;
4359 return true;
4361 else
4363 // a child window got the focus so update current item to
4364 // allow for proper lose focus handling in keyboard navigation
4365 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
4366 while( it != mpData->m_aItems.end() )
4368 if ( it->mbVisible )
4370 if ( it->mpWindow && it->mpWindow->ImplIsWindowOrChild( rNEvt.GetWindow() ) )
4372 mnHighItemId = it->mnId;
4373 break;
4377 ++it;
4379 return DockingWindow::EventNotify( rNEvt );
4382 else if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
4384 // deselect
4385 ImplHideFocus();
4386 mnHighItemId = 0;
4387 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
4390 return DockingWindow::EventNotify( rNEvt );
4393 void ToolBox::Command( const CommandEvent& rCEvt )
4395 maCommandHandler.Call( &rCEvt );
4397 // depict StartDrag on MouseButton/Left/Alt
4398 if ( (rCEvt.GetCommand() == CommandEventId::StartDrag) && rCEvt.IsMouseEvent() &&
4399 mbCustomize && !mbDragging && !mbDrag && !mbSelection &&
4400 (mnCurPos == TOOLBOX_ITEM_NOTFOUND) )
4402 // We only allow dragging of items. Therefore, we have to check
4403 // if an item was clicked, otherwise we could move the window, and
4404 // this is unwanted.
4405 // We only do this in customize mode, as otherwise
4406 // items could be moved accidentally
4407 if ( mbCustomizeMode )
4409 Point aMousePos = rCEvt.GetMousePosPixel();
4410 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
4411 while ( it != mpData->m_aItems.end() )
4413 // is this the item?
4414 if ( it->maRect.IsInside( aMousePos ) )
4416 // do nothing if it is a separator or
4417 // the item has been disabled
4418 if ( (it->meType == ToolBoxItemType::BUTTON) &&
4419 !it->mbShowWindow )
4420 mbCommandDrag = true;
4421 break;
4424 ++it;
4427 if ( mbCommandDrag )
4429 MouseEvent aMEvt( aMousePos, 1, MouseEventModifiers::SIMPLEMOVE,
4430 MOUSE_LEFT, KEY_MOD2 );
4431 ToolBox::MouseButtonDown( aMEvt );
4432 return;
4436 else if ( rCEvt.GetCommand() == CommandEventId::Wheel )
4438 if ( (mnCurLine > 1) || (mnCurLine+mnVisLines-1 < mnCurLines) )
4440 const CommandWheelData* pData = rCEvt.GetWheelData();
4441 if ( pData->GetMode() == CommandWheelMode::SCROLL )
4443 if ( (mnCurLine > 1) && (pData->GetDelta() > 0) )
4444 ShowLine( false );
4445 else if ( (mnCurLine+mnVisLines-1 < mnCurLines) && (pData->GetDelta() < 0) )
4446 ShowLine( true );
4447 InvalidateSpin();
4448 return;
4453 DockingWindow::Command( rCEvt );
4456 void ToolBox::StateChanged( StateChangedType nType )
4458 DockingWindow::StateChanged( nType );
4460 if ( nType == StateChangedType::InitShow )
4461 ImplFormat();
4462 else if ( nType == StateChangedType::Enable )
4463 ImplUpdateItem();
4464 else if ( nType == StateChangedType::UpdateMode )
4466 if ( IsUpdateMode() )
4467 Invalidate();
4469 else if ( (nType == StateChangedType::Zoom) ||
4470 (nType == StateChangedType::ControlFont) )
4472 mbCalc = true;
4473 mbFormat = true;
4474 ImplInitSettings( true, false, false );
4475 Invalidate();
4477 else if ( nType == StateChangedType::ControlForeground )
4479 ImplInitSettings( false, true, false );
4480 Invalidate();
4482 else if ( nType == StateChangedType::ControlBackground )
4484 ImplInitSettings( false, false, true ); // font, foreground, background
4485 Invalidate();
4488 maStateChangedHandler.Call( &nType );
4491 void ToolBox::DataChanged( const DataChangedEvent& rDCEvt )
4493 DockingWindow::DataChanged( rDCEvt );
4495 if ( (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
4496 (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
4497 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
4498 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
4499 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
4501 mbCalc = true;
4502 mbFormat = true;
4503 ImplInitSettings( true, true, true );
4504 Invalidate();
4507 maDataChangedHandler.Call( &rDCEvt );
4510 void ToolBox::statusChanged( const css::frame::FeatureStateEvent& Event )
4512 // Update image mirroring/rotation
4513 if ( Event.FeatureURL.Complete == ".uno:ImageOrientation" )
4515 SfxImageItem aItem( 1 );
4516 aItem.PutValue( Event.State, 0 );
4518 mbImagesMirrored = aItem.IsMirrored();
4519 mnImagesRotationAngle = aItem.GetRotation();
4521 // update image orientation
4522 for (std::vector<ImplToolItem>::const_iterator it = mpData->m_aItems.begin(); it != mpData->m_aItems.end(); ++it)
4524 if (vcl::CommandInfoProvider::Instance().IsMirrored(it->maCommandStr))
4525 SetItemImageMirrorMode(it->mnId, mbImagesMirrored);
4526 if (vcl::CommandInfoProvider::Instance().IsRotated(it->maCommandStr))
4527 SetItemImageAngle(it->mnId, mnImagesRotationAngle);
4532 void ToolBox::SetStyle(WinBits nNewStyle)
4534 mnWinStyle = nNewStyle;
4535 if (!ImplIsFloatingMode())
4537 bool bOldScroll = mbScroll;
4538 mbScroll = (mnWinStyle & WB_SCROLL) != 0;
4539 if (mbScroll != bOldScroll)
4541 mbFormat = true;
4542 ImplFormat();
4547 void ToolBox::ToggleFloatingMode()
4549 DockingWindow::ToggleFloatingMode();
4551 if (!mpData)
4552 return;
4554 bool bOldHorz = mbHorz;
4556 if ( ImplIsFloatingMode() )
4558 mbHorz = true;
4559 meAlign = WindowAlign::Top;
4560 mbScroll = true;
4562 if( bOldHorz != mbHorz )
4563 mbCalc = true; // orientation was changed !
4565 ImplSetMinMaxFloatSize( this );
4566 SetOutputSizePixel( ImplCalcFloatSize( this, mnFloatLines ) );
4568 else
4570 mbScroll = (mnWinStyle & WB_SCROLL) != 0;
4571 if ( (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom) )
4572 mbHorz = true;
4573 else
4574 mbHorz = false;
4576 // set focus back to document
4577 ImplGetFrameWindow()->GetWindow( GetWindowType::Client )->GrabFocus();
4580 if( bOldHorz != mbHorz )
4582 // if orientation changes, the toolbox has to be initialized again
4583 // to update the direction of the gradient
4584 mbCalc = true;
4585 ImplInitSettings( true, true, true );
4588 mbFormat = true;
4589 ImplFormat();
4592 void ToolBox::StartDocking()
4594 meDockAlign = meAlign;
4595 mnDockLines = mnLines;
4596 mbLastFloatMode = ImplIsFloatingMode();
4597 DockingWindow::StartDocking();
4600 bool ToolBox::Docking( const Point& rPos, Rectangle& rRect )
4602 // do nothing during dragging, it was calculated before
4603 if ( mbDragging )
4604 return false;
4606 bool bFloatMode = false;
4608 DockingWindow::Docking( rPos, rRect );
4610 // if the mouse is outside the area, it can only become a floating window
4611 Rectangle aDockingRect( rRect );
4612 if ( !ImplIsFloatingMode() )
4614 // don't use tracking rectangle for alignment check, because it will be too large
4615 // to get a floating mode as result - switch to floating size
4616 // so the calculation only depends on the position of the rectangle, not the current
4617 // docking state of the window
4618 sal_uInt16 nTemp = 0;
4619 aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) );
4621 // in this mode docking is never done by keyboard, so it's OK to use the mouse position
4622 aDockingRect.SetPos( ImplGetFrameWindow()->GetPointerPosPixel() );
4625 Rectangle aIntersection = maOutDockRect.GetIntersection( aDockingRect );
4626 if ( !aIntersection.IsEmpty() )
4628 Rectangle aInRect = maInDockRect;
4629 Size aDockSize;
4630 aDockSize.Width() = ImplCalcSize( this, mnLines, TB_CALCMODE_VERT ).Width();
4631 aDockSize.Height() = ImplCalcSize( this, mnLines, TB_CALCMODE_HORZ ).Height();
4632 aInRect.Left() += aDockSize.Width()/2;
4633 aInRect.Top() += aDockSize.Height()/2;
4634 aInRect.Right() -= aDockSize.Width()/2;
4635 aInRect.Bottom() -= aDockSize.Height()/2;
4637 // if the window is too small, use the complete InDock-Rect
4638 if ( aInRect.Left() >= aInRect.Right() )
4640 aInRect.Left() = maInDockRect.Left();
4641 aInRect.Right() = maInDockRect.Right();
4643 if ( aInRect.Top() >= aInRect.Bottom() )
4645 aInRect.Top() = maInDockRect.Top();
4646 aInRect.Bottom() = maInDockRect.Bottom();
4649 // if the mouse is outside the Dock area, it can only
4650 // become a floating window
4651 Rectangle aIntersect = aInRect.GetIntersection( aDockingRect );
4652 if ( aIntersect == aDockingRect )
4653 bFloatMode = true;
4654 else
4656 // docking rectangle is in the "sensible area"
4657 Point aPos = aDockingRect.TopLeft();
4658 Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() );
4659 Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() );
4660 Size aInSize = aInRect.GetSize();
4662 if ( aInPosTL.X() <= 0 )
4663 meDockAlign = WindowAlign::Left;
4664 else if ( aInPosTL.Y() <= 0)
4665 meDockAlign = WindowAlign::Top;
4666 else if ( aInPosBR.X() >= aInSize.Width() )
4667 meDockAlign = WindowAlign::Right;
4668 else if ( aInPosBR.Y() >= aInSize.Height() )
4669 meDockAlign = WindowAlign::Bottom;
4671 // update the Dock size if Dock-Align was changed
4672 if ( (meDockAlign == WindowAlign::Top) || (meDockAlign == WindowAlign::Bottom) )
4673 aDockSize.Width() = maInDockRect.GetWidth();
4674 else
4675 aDockSize.Height() = maInDockRect.GetHeight();
4677 aDockingRect.SetSize( aDockSize );
4679 Point aPosTL( maInDockRect.TopLeft() );
4680 switch ( meDockAlign )
4682 case WindowAlign::Top :
4683 aDockingRect.SetPos( aPosTL );
4684 break;
4685 case WindowAlign::Left :
4686 aDockingRect.SetPos( aPosTL );
4687 break;
4688 case WindowAlign::Bottom :
4690 Point aPosBL( maInDockRect.BottomLeft() );
4691 aPosBL.Y() -= aDockingRect.GetHeight();
4692 aDockingRect.SetPos( aPosBL );
4693 break;
4695 case WindowAlign::Right :
4697 Point aPosTR( maInDockRect.TopRight() );
4698 aPosTR.X() -= aDockingRect.GetWidth();
4699 aDockingRect.SetPos( aPosTR );
4700 break;
4705 else
4706 bFloatMode = true;
4708 if ( bFloatMode )
4710 meDockAlign = meAlign;
4711 if ( !mbLastFloatMode )
4713 sal_uInt16 nTemp = 0;
4714 aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) );
4718 rRect = aDockingRect;
4719 mbLastFloatMode = bFloatMode;
4721 return bFloatMode;
4724 void ToolBox::EndDocking( const Rectangle& rRect, bool bFloatMode )
4726 if ( !IsDockingCanceled() )
4728 if ( mnLines != mnDockLines )
4729 SetLineCount( mnDockLines );
4730 if ( meAlign != meDockAlign )
4731 SetAlign( meDockAlign );
4733 if ( bFloatMode || (bool(bFloatMode) != ImplIsFloatingMode()) )
4734 DockingWindow::EndDocking( rRect, bFloatMode );
4737 void ToolBox::Resizing( Size& rSize )
4739 sal_uInt16 nCalcLines;
4740 sal_uInt16 nTemp;
4742 // Alle Floatinggroessen berechnen
4743 ImplCalcFloatSizes( this );
4745 if ( !mnLastResizeDY )
4746 mnLastResizeDY = mnDY;
4748 // Ist vertikales Resizing angesagt
4749 if ( (mnLastResizeDY != rSize.Height()) && (mnDY != rSize.Height()) )
4751 nCalcLines = ImplCalcLines( this, rSize.Height() );
4752 if ( nCalcLines < 1 )
4753 nCalcLines = 1;
4754 rSize = ImplCalcFloatSize( this, nCalcLines );
4756 else
4758 nCalcLines = 1;
4759 nTemp = nCalcLines;
4760 Size aTempSize = ImplCalcFloatSize( this, nTemp );
4761 while ( (aTempSize.Width() > rSize.Width()) &&
4762 (nCalcLines <= maFloatSizes[0].mnLines) )
4764 nCalcLines++;
4765 nTemp = nCalcLines;
4766 aTempSize = ImplCalcFloatSize( this, nTemp );
4768 rSize = aTempSize;
4771 mnLastResizeDY = rSize.Height();
4774 Size ToolBox::GetOptimalSize() const
4776 // If we have any expandable entries, then force them to their
4777 // optimal sizes, then reset them afterwards
4778 std::map<vcl::Window*, Size> aExpandables;
4779 for (ImplToolItem & rItem : mpData->m_aItems)
4781 if (rItem.mbExpand)
4783 vcl::Window *pWindow = rItem.mpWindow;
4784 SAL_INFO_IF(!pWindow, "vcl.layout", "only tabitems with window supported at the moment");
4785 if (!pWindow)
4786 continue;
4787 Size aWinSize(pWindow->GetSizePixel());
4788 aExpandables[pWindow] = aWinSize;
4789 Size aPrefSize(pWindow->get_preferred_size());
4790 aWinSize.Width() = aPrefSize.Width();
4791 pWindow->SetSizePixel(aWinSize);
4795 Size aSize(ImplCalcSize( this, mnLines ));
4797 for (std::map<vcl::Window*, Size>::iterator aI = aExpandables.begin(); aI != aExpandables.end(); ++aI)
4799 vcl::Window *pWindow = aI->first;
4800 Size aWinSize = aI->second;
4801 pWindow->SetSizePixel(aWinSize);
4804 return aSize;
4807 Size ToolBox::CalcWindowSizePixel( sal_uInt16 nCalcLines ) const
4809 return ImplCalcSize( this, nCalcLines );
4812 Size ToolBox::CalcWindowSizePixel( sal_uInt16 nCalcLines, WindowAlign eAlign ) const
4814 return ImplCalcSize( this, nCalcLines,
4815 (eAlign == WindowAlign::Top || eAlign == WindowAlign::Bottom) ? TB_CALCMODE_HORZ : TB_CALCMODE_VERT );
4818 sal_uInt16 ToolBox::ImplCountLineBreaks( const ToolBox *pThis )
4820 sal_uInt16 nLines = 0;
4822 std::vector< ImplToolItem >::const_iterator it = const_cast<ToolBox*>(pThis)->mpData->m_aItems.begin();
4823 while ( it != const_cast<ToolBox*>(pThis)->mpData->m_aItems.end() )
4825 if( it->meType == ToolBoxItemType::BREAK )
4826 ++nLines;
4827 ++it;
4829 return nLines;
4832 Size ToolBox::CalcPopupWindowSizePixel() const
4834 // count number of breaks and calc corresponding floating window size
4835 sal_uInt16 nLines = ImplCountLineBreaks( this );
4837 if( nLines )
4838 ++nLines; // add the first line
4839 else
4841 // no breaks found: use quadratic layout
4842 nLines = (sal_uInt16) ceil( sqrt( (double) GetItemCount() ) );
4845 bool bPopup = mpData->mbAssumePopupMode;
4846 ToolBox *pThis = const_cast<ToolBox*>(this);
4847 pThis->mpData->mbAssumePopupMode = true;
4849 Size aSize = CalcFloatingWindowSizePixel( nLines );
4851 pThis->mpData->mbAssumePopupMode = bPopup;
4852 return aSize;
4855 Size ToolBox::CalcFloatingWindowSizePixel() const
4857 sal_uInt16 nLines = ImplCountLineBreaks( this );
4858 ++nLines; // add the first line
4859 return CalcFloatingWindowSizePixel( nLines );
4862 Size ToolBox::CalcFloatingWindowSizePixel( sal_uInt16 nCalcLines ) const
4864 bool bFloat = mpData->mbAssumeFloating;
4865 bool bDocking = mpData->mbAssumeDocked;
4867 // simulate floating mode and force reformat before calculating
4868 ToolBox *pThis = const_cast<ToolBox*>(this);
4869 pThis->mpData->mbAssumeFloating = true;
4870 pThis->mpData->mbAssumeDocked = false;
4872 Size aSize = ImplCalcFloatSize( const_cast<ToolBox*>(this), nCalcLines );
4874 pThis->mbFormat = true;
4875 pThis->mpData->mbAssumeFloating = bFloat;
4876 pThis->mpData->mbAssumeDocked = bDocking;
4878 return aSize;
4881 Size ToolBox::CalcMinimumWindowSizePixel() const
4883 if( ImplIsFloatingMode() )
4884 return ImplCalcSize( this, mnFloatLines );
4885 else
4887 // create dummy toolbox for measurements
4888 VclPtrInstance< ToolBox > pToolBox( GetParent(), GetStyle() );
4890 // copy until first useful item
4891 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
4892 while( it != mpData->m_aItems.end() )
4894 pToolBox->CopyItem( *this, it->mnId );
4895 if( (it->meType != ToolBoxItemType::BUTTON) ||
4896 !it->mbVisible || ImplIsFixedControl( &(*it) ) )
4897 ++it;
4898 else
4899 break;
4902 // add to docking manager if required to obtain a drag area
4903 // (which is accounted for in calcwindowsizepixel)
4904 if( ImplGetDockingManager()->GetDockingWindowWrapper( this ) )
4905 ImplGetDockingManager()->AddWindow( pToolBox );
4907 // account for menu
4908 if( IsMenuEnabled() )
4909 pToolBox->SetMenuType( GetMenuType() );
4911 pToolBox->SetAlign( GetAlign() );
4912 Size aSize = pToolBox->CalcWindowSizePixel( 1 );
4914 ImplGetDockingManager()->RemoveWindow( pToolBox );
4915 pToolBox->Clear();
4917 pToolBox.disposeAndClear();
4919 return aSize;
4923 void ToolBox::EnableCustomize( bool bEnable )
4925 if ( bEnable != mbCustomize )
4927 mbCustomize = bEnable;
4929 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
4930 if ( bEnable )
4931 pMgr->push_back( this );
4932 else
4933 pMgr->erase( this );
4937 void ToolBox::LoseFocus()
4939 ImplChangeHighlight( nullptr, true );
4941 DockingWindow::LoseFocus();
4944 // performs the action associated with an item, ie simulates clicking the item
4945 void ToolBox::TriggerItem( sal_uInt16 nItemId )
4947 mnHighItemId = nItemId;
4948 sal_uInt16 nModifier = 0;
4949 vcl::KeyCode aKeyCode( 0, nModifier );
4950 ImplActivateItem( aKeyCode );
4953 // calls the button's action handler
4954 // returns true if action was called
4955 bool ToolBox::ImplActivateItem( vcl::KeyCode aKeyCode )
4957 bool bRet = true;
4958 if( mnHighItemId )
4960 ImplToolItem *pToolItem = ImplGetItem( mnHighItemId );
4962 // #107712#, activate can also be called for disabled entries
4963 if( pToolItem && !pToolItem->mbEnabled )
4964 return true;
4966 if( pToolItem && pToolItem->mpWindow && HasFocus() )
4968 ImplHideFocus();
4969 mbChangingHighlight = true; // avoid focus change due to loss of focus
4970 pToolItem->mpWindow->ImplControlFocus( GetFocusFlags::Tab );
4971 mbChangingHighlight = false;
4973 else
4975 mnDownItemId = mnCurItemId = mnHighItemId;
4976 if (pToolItem && (pToolItem->mnBits & ToolBoxItemBits::AUTOCHECK))
4978 if ( pToolItem->mnBits & ToolBoxItemBits::RADIOCHECK )
4980 if ( pToolItem->meState != TRISTATE_TRUE )
4981 SetItemState( pToolItem->mnId, TRISTATE_TRUE );
4983 else
4985 if ( pToolItem->meState != TRISTATE_TRUE )
4986 pToolItem->meState = TRISTATE_TRUE;
4987 else
4988 pToolItem->meState = TRISTATE_FALSE;
4991 mnMouseModifier = aKeyCode.GetModifier();
4992 mbIsKeyEvent = true;
4993 Activate();
4994 Click();
4996 // #107776# we might be destroyed in the selecthandler
4997 VclPtr<vcl::Window> xWindow = this;
4998 Select();
4999 if ( xWindow->IsDisposed() )
5000 return bRet;
5002 Deactivate();
5003 mbIsKeyEvent = false;
5004 mnMouseModifier = 0;
5007 else
5008 bRet = false;
5009 return bRet;
5012 bool ImplCloseLastPopup( vcl::Window *pParent )
5014 // close last popup toolbox (see also:
5015 // ImplHandleMouseFloatMode(...) in winproc.cxx )
5017 if( ImplGetSVData()->maWinData.mpFirstFloat )
5019 FloatingWindow* pLastLevelFloat = ImplGetSVData()->maWinData.mpFirstFloat->ImplFindLastLevelFloat();
5020 // only close the floater if it is not our direct parent, which would kill ourself
5021 if( pLastLevelFloat && pLastLevelFloat != pParent )
5023 pLastLevelFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
5024 return true;
5027 return false;
5030 // opens a drop down toolbox item
5031 // returns true if item was opened
5032 bool ToolBox::ImplOpenItem( vcl::KeyCode aKeyCode )
5034 sal_uInt16 nCode = aKeyCode.GetCode();
5035 bool bRet = true;
5037 // arrow keys should work only in the opposite direction of alignment (to not break cursor travelling)
5038 if ( ((nCode == KEY_LEFT || nCode == KEY_RIGHT) && IsHorizontal())
5039 || ((nCode == KEY_UP || nCode == KEY_DOWN) && !IsHorizontal()) )
5040 return false;
5042 if( IsMenuEnabled() && mpData->mbMenubuttonSelected )
5044 if( ImplCloseLastPopup( GetParent() ) )
5045 return bRet;
5047 UpdateCustomMenu();
5048 mpData->mnEventId = Application::PostUserEvent( LINK( this, ToolBox, ImplCallExecuteCustomMenu ), nullptr, true );
5050 else if( mnHighItemId && ImplGetItem( mnHighItemId ) &&
5051 (ImplGetItem( mnHighItemId )->mnBits & ToolBoxItemBits::DROPDOWN) )
5053 if( ImplCloseLastPopup( GetParent() ) )
5054 return bRet;
5056 mnDownItemId = mnCurItemId = mnHighItemId;
5057 mnCurPos = GetItemPos( mnCurItemId );
5058 mnLastFocusItemId = mnCurItemId; // save item id for possible later focus restore
5059 mnMouseModifier = aKeyCode.GetModifier();
5060 mbIsShift = true;
5061 mbIsKeyEvent = true;
5062 Activate();
5064 mpData->mbDropDownByKeyboard = true;
5065 mpData->maDropdownClickHdl.Call( this );
5067 mbIsKeyEvent = false;
5068 mbIsShift = false;
5069 mnMouseModifier = 0;
5071 else
5072 bRet = false;
5074 return bRet;
5077 void ToolBox::KeyInput( const KeyEvent& rKEvt )
5079 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
5080 mnKeyModifier = aKeyCode.GetModifier();
5081 sal_uInt16 nCode = aKeyCode.GetCode();
5083 vcl::Window *pParent = ImplGetParent();
5084 bool bOldSchoolContainer = ((pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL);
5085 bool bParentIsContainer = bOldSchoolContainer || isContainerWindow(pParent);
5087 bool bForwardKey = false;
5088 bool bGrabFocusToDocument = false;
5090 // #107776# we might be destroyed in the keyhandler
5091 VclPtr<vcl::Window> xWindow = this;
5093 switch ( nCode )
5095 case KEY_UP:
5097 // Ctrl-Cursor activates next toolbox, indicated by a blue arrow pointing to the left/up
5098 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
5099 break;
5100 if( !IsHorizontal() )
5101 ImplChangeHighlightUpDn( true );
5102 else
5103 ImplOpenItem( aKeyCode );
5105 break;
5106 case KEY_LEFT:
5108 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
5109 break;
5110 if( IsHorizontal() )
5111 ImplChangeHighlightUpDn( true );
5112 else
5113 ImplOpenItem( aKeyCode );
5115 break;
5116 case KEY_DOWN:
5118 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
5119 break;
5120 if( !IsHorizontal() )
5121 ImplChangeHighlightUpDn( false );
5122 else
5123 ImplOpenItem( aKeyCode );
5125 break;
5126 case KEY_RIGHT:
5128 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
5129 break;
5130 if( IsHorizontal() )
5131 ImplChangeHighlightUpDn( false );
5132 else
5133 ImplOpenItem( aKeyCode );
5135 break;
5136 case KEY_PAGEUP:
5137 if ( mnCurLine > 1 )
5139 if( mnCurLine > mnVisLines )
5140 mnCurLine = mnCurLine - mnVisLines;
5141 else
5142 mnCurLine = 1;
5143 mbFormat = true;
5144 ImplFormat();
5145 InvalidateSpin();
5146 ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
5148 break;
5149 case KEY_PAGEDOWN:
5150 if ( mnCurLine+mnVisLines-1 < mnCurLines )
5152 if( mnCurLine + 2*mnVisLines-1 < mnCurLines )
5153 mnCurLine = mnCurLine + mnVisLines;
5154 else
5155 mnCurLine = mnCurLines;
5156 mbFormat = true;
5157 ImplFormat();
5158 InvalidateSpin();
5159 ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
5161 break;
5162 case KEY_END:
5164 ImplChangeHighlight( nullptr );
5165 ImplChangeHighlightUpDn( false );
5167 break;
5168 case KEY_HOME:
5170 ImplChangeHighlight( nullptr );
5171 ImplChangeHighlightUpDn( true );
5173 break;
5174 case KEY_ESCAPE:
5176 if( !ImplIsFloatingMode() && bParentIsContainer )
5177 DockingWindow::KeyInput( rKEvt );
5178 else
5180 // send focus to document pane
5181 vcl::Window *pWin = this;
5182 while( pWin )
5184 if( !pWin->GetParent() )
5186 pWin->ImplGetFrameWindow()->GetWindow( GetWindowType::Client )->GrabFocus();
5187 break;
5189 pWin = pWin->GetParent();
5193 break;
5194 case KEY_RETURN:
5196 // #107712#, disabled entries are selectable now
5197 // leave toolbox and move focus to document
5198 if( mnHighItemId )
5200 ImplToolItem *pItem = ImplGetItem( mnHighItemId );
5201 if( !pItem->mbEnabled )
5203 bGrabFocusToDocument = true;
5206 if( !bGrabFocusToDocument )
5207 bForwardKey = !ImplActivateItem( aKeyCode );
5209 break;
5210 case KEY_SPACE:
5212 ImplOpenItem( aKeyCode );
5214 break;
5215 default:
5217 sal_uInt16 aKeyGroup = aKeyCode.GetGroup();
5218 ImplToolItem *pItem = nullptr;
5219 if( mnHighItemId )
5220 pItem = ImplGetItem( mnHighItemId );
5221 // #i13931# forward alphanum keyinput into embedded control
5222 if( (aKeyGroup == KEYGROUP_NUM || aKeyGroup == KEYGROUP_ALPHA ) && pItem && pItem->mpWindow && pItem->mbEnabled )
5224 vcl::Window *pFocusWindow = Application::GetFocusWindow();
5225 ImplHideFocus();
5226 mbChangingHighlight = true; // avoid focus change due to loss of focus
5227 pItem->mpWindow->ImplControlFocus( GetFocusFlags::Tab );
5228 mbChangingHighlight = false;
5229 if( pFocusWindow != Application::GetFocusWindow() )
5230 Application::GetFocusWindow()->KeyInput( rKEvt );
5232 else
5234 // do nothing to avoid key presses going into the document
5235 // while the toolbox has the focus
5236 // just forward function and special keys and combinations with Alt-key
5237 if( aKeyGroup == KEYGROUP_FKEYS || aKeyGroup == KEYGROUP_MISC || aKeyCode.IsMod2() )
5238 bForwardKey = true;
5243 if ( xWindow->IsDisposed() )
5244 return;
5246 // #107251# move focus away if this toolbox was disabled during keyinput
5247 if (HasFocus() && mpData->mbKeyInputDisabled && bParentIsContainer)
5249 sal_uInt16 n = 0;
5250 vcl::Window *pFocusControl = pParent->ImplGetDlgWindow( n, GetDlgWindowType::First );
5251 if ( pFocusControl && pFocusControl != this )
5252 pFocusControl->ImplControlFocus( GetFocusFlags::Init );
5255 mnKeyModifier = 0;
5257 // #107712#, leave toolbox
5258 if( bGrabFocusToDocument )
5260 GrabFocusToDocument();
5261 return;
5264 if( bForwardKey )
5265 DockingWindow::KeyInput( rKEvt );
5268 // returns the current toolbox line of the item
5269 sal_uInt16 ToolBox::ImplGetItemLine( ImplToolItem* pCurrentItem )
5271 std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin();
5272 sal_uInt16 nLine = 1;
5273 while( it != mpData->m_aItems.end() )
5275 if ( it->mbBreak )
5276 ++nLine;
5277 if( &(*it) == pCurrentItem)
5278 break;
5279 ++it;
5281 return nLine;
5284 // returns the first displayable item in the given line
5285 ImplToolItem* ToolBox::ImplGetFirstValidItem( sal_uInt16 nLine )
5287 if( !nLine || nLine > mnCurLines )
5288 return nullptr;
5290 nLine--;
5292 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
5293 while( it != mpData->m_aItems.end() )
5295 // find correct line
5296 if ( it->mbBreak )
5297 nLine--;
5298 if( !nLine )
5300 // find first useful item
5301 while( it != mpData->m_aItems.end() && ((it->meType != ToolBoxItemType::BUTTON) ||
5302 /*!it->mbEnabled ||*/ !it->mbVisible || ImplIsFixedControl( &(*it) )) )
5304 ++it;
5305 if( it == mpData->m_aItems.end() || it->mbBreak )
5306 return nullptr; // no valid items in this line
5308 return &(*it);
5310 ++it;
5313 return (it == mpData->m_aItems.end()) ? nullptr : &(*it);
5316 sal_uInt16 ToolBox::ImplFindItemPos( const ImplToolItem* pItem, const std::vector< ImplToolItem >& rList )
5318 if( pItem )
5320 sal_uInt16 nPos;
5321 for( nPos = 0; nPos < rList.size(); ++nPos )
5322 if( &rList[ nPos ] == pItem )
5323 return nPos;
5325 return TOOLBOX_ITEM_NOTFOUND;
5328 void ToolBox::ChangeHighlight( sal_uInt16 nPos )
5330 if ( nPos < GetItemCount() ) {
5331 ImplGrabFocus( GetFocusFlags::NONE );
5332 ImplChangeHighlight ( ImplGetItem ( GetItemId ( (sal_uInt16) nPos ) ) );
5336 void ToolBox::ImplChangeHighlight( ImplToolItem* pItem, bool bNoGrabFocus )
5338 // avoid recursion due to focus change
5339 if( mbChangingHighlight )
5340 return;
5342 mbChangingHighlight = true;
5344 ImplToolItem* pOldItem = nullptr;
5346 if ( mnHighItemId )
5348 ImplHideFocus();
5349 sal_uInt16 nPos = GetItemPos( mnHighItemId );
5350 pOldItem = ImplGetItem( mnHighItemId );
5351 // #i89962# ImplDrawItem can cause Invalidate/Update
5352 // which will in turn ImplShowFocus again
5353 // set mnHighItemId to 0 already to prevent this hen/egg problem
5354 mnHighItemId = 0;
5355 InvalidateItem(nPos);
5356 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) );
5359 if( !bNoGrabFocus && pItem != pOldItem && pOldItem && pOldItem->mpWindow )
5361 // move focus into toolbox
5362 GrabFocus();
5365 if( pItem )
5367 sal_uInt16 aPos = ToolBox::ImplFindItemPos( pItem, mpData->m_aItems );
5368 if( aPos != TOOLBOX_ITEM_NOTFOUND)
5370 // check for line breaks
5371 sal_uInt16 nLine = ImplGetItemLine( pItem );
5373 if( nLine >= mnCurLine + mnVisLines )
5375 mnCurLine = nLine - mnVisLines + 1;
5376 mbFormat = true;
5378 else if ( nLine < mnCurLine )
5380 mnCurLine = nLine;
5381 mbFormat = true;
5384 if( mbFormat )
5386 ImplFormat();
5389 mnHighItemId = pItem->mnId;
5390 InvalidateItem(aPos);
5392 if( mbSelection )
5393 mnCurPos = aPos;
5394 ImplShowFocus();
5396 if( pItem->mpWindow )
5397 pItem->mpWindow->GrabFocus();
5398 if( pItem != pOldItem )
5399 CallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT );
5402 else
5404 ImplHideFocus();
5405 mnHighItemId = 0;
5406 mnCurPos = TOOLBOX_ITEM_NOTFOUND;
5409 mbChangingHighlight = false;
5412 // check for keyboard accessible items
5413 static bool ImplIsValidItem( const ImplToolItem* pItem, bool bNotClipped )
5415 bool bValid = (pItem && pItem->meType == ToolBoxItemType::BUTTON && pItem->mbVisible && !ImplIsFixedControl( pItem ));
5416 if( bValid && bNotClipped && pItem->IsClipped() )
5417 bValid = false;
5418 return bValid;
5421 bool ToolBox::ImplChangeHighlightUpDn( bool bUp, bool bNoCycle )
5423 ImplToolItem* pToolItem = ImplGetItem( mnHighItemId );
5425 if( !pToolItem || !mnHighItemId )
5427 // menubutton highlighted ?
5428 if( mpData->mbMenubuttonSelected )
5430 if( bUp )
5432 // select last valid non-clipped item
5433 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end();
5434 ImplToolItem* pItem = nullptr;
5435 while( it != mpData->m_aItems.begin() )
5437 --it;
5438 if ( ImplIsValidItem( &(*it), true ) )
5440 pItem = &(*it);
5441 break;
5444 InvalidateMenuButton();
5445 ImplChangeHighlight( pItem );
5447 else
5449 // select first valid non-clipped item
5450 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
5451 while( it != mpData->m_aItems.end() )
5453 if ( ImplIsValidItem( &(*it), true ) )
5454 break;
5455 ++it;
5457 if( it != mpData->m_aItems.end() )
5459 InvalidateMenuButton();
5460 ImplChangeHighlight( &(*it) );
5463 return true;
5466 if( bUp )
5468 // Select first valid item
5469 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin();
5470 while( it != mpData->m_aItems.end() )
5472 if ( ImplIsValidItem( &(*it), false ) )
5473 break;
5474 ++it;
5477 // select the menu button if a clipped item would be selected
5478 if( (it != mpData->m_aItems.end() && &(*it) == ImplGetFirstClippedItem( this )) && IsMenuEnabled() )
5480 ImplChangeHighlight( nullptr );
5481 InvalidateMenuButton();
5483 else
5484 ImplChangeHighlight( (it != mpData->m_aItems.end()) ? &(*it) : nullptr );
5485 return true;
5487 else
5489 // Select last valid item
5491 // docked toolbars have the menubutton as last item - if this button is enabled
5492 if( IsMenuEnabled() && !ImplIsFloatingMode() )
5494 ImplChangeHighlight( nullptr );
5495 InvalidateMenuButton();
5497 else
5499 std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end();
5500 ImplToolItem* pItem = nullptr;
5501 while( it != mpData->m_aItems.begin() )
5503 --it;
5504 if ( ImplIsValidItem( &(*it), false ) )
5506 pItem = &(*it);
5507 break;
5510 ImplChangeHighlight( pItem );
5512 return true;
5516 if( pToolItem )
5518 sal_uLong pos = ToolBox::ImplFindItemPos( pToolItem, mpData->m_aItems );
5519 sal_uLong nCount = mpData->m_aItems.size();
5521 sal_uLong i=0;
5524 if( bUp )
5526 if( !pos-- )
5528 if( bNoCycle )
5529 return false;
5531 // highlight the menu button if it is the last item
5532 if( IsMenuEnabled() && !ImplIsFloatingMode() )
5534 ImplChangeHighlight( nullptr );
5535 InvalidateMenuButton();
5536 return true;
5538 else
5539 pos = nCount-1;
5542 else
5544 if( ++pos >= nCount )
5546 if( bNoCycle )
5547 return false;
5549 // highlight the menu button if it is the last item
5550 if( IsMenuEnabled() && !ImplIsFloatingMode() )
5552 ImplChangeHighlight( nullptr );
5553 InvalidateMenuButton();
5554 return true;
5556 else
5557 pos = 0;
5561 pToolItem = &mpData->m_aItems[pos];
5563 if ( ImplIsValidItem( pToolItem, false ) )
5564 break;
5566 } while( ++i < nCount);
5568 if( pToolItem->IsClipped() && IsMenuEnabled() )
5570 // select the menu button if a clipped item would be selected
5571 ImplChangeHighlight( nullptr );
5572 InvalidateMenuButton();
5574 else if( i != nCount )
5575 ImplChangeHighlight( pToolItem );
5576 else
5577 return false;
5579 return true;
5582 void ToolBox::ImplShowFocus()
5584 if( mnHighItemId && HasFocus() )
5586 ImplToolItem* pItem = ImplGetItem( mnHighItemId );
5587 if( pItem->mpWindow && !pItem->mpWindow->IsDisposed() )
5589 vcl::Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow.get() : pItem->mpWindow.get();
5590 pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = true;
5591 pWin->Invalidate();
5596 void ToolBox::ImplHideFocus()
5598 if( mnHighItemId )
5600 ImplToolItem* pItem = ImplGetItem( mnHighItemId );
5601 if( pItem && pItem->mpWindow )
5603 vcl::Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow.get() : pItem->mpWindow.get();
5604 pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = false;
5605 pWin->Invalidate();
5609 if ( mpData && mpData->mbMenubuttonSelected )
5611 // remove highlight from menubutton
5612 InvalidateMenuButton();
5616 void ToolBox::ImplDisableFlatButtons()
5618 #ifdef _WIN32 // Check in the Windows registry if an AT tool wants no flat toolboxes
5619 static bool bInit = false, bValue = false;
5620 if( ! bInit )
5622 bInit = true;
5623 HKEY hkey;
5625 if( ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, "Software\\LibreOffice\\Accessibility\\AtToolSupport", &hkey) )
5627 DWORD dwType = 0;
5628 sal_uInt8 Data[6]; // possible values: "true", "false", "1", "0", DWORD
5629 DWORD cbData = sizeof(Data);
5631 if( ERROR_SUCCESS == RegQueryValueEx(hkey, "DisableFlatToolboxButtons",
5632 nullptr, &dwType, Data, &cbData) )
5634 switch (dwType)
5636 case REG_SZ:
5637 bValue = ((0 == stricmp(reinterpret_cast<const char *>(Data), "1")) || (0 == stricmp(reinterpret_cast<const char *>(Data), "true")));
5638 break;
5639 case REG_DWORD:
5640 bValue = (bool)(reinterpret_cast<DWORD *>(Data)[0]);
5641 break;
5644 RegCloseKey(hkey);
5647 if( bValue )
5648 mnOutStyle &= ~TOOLBOX_STYLE_FLAT;
5649 #else
5650 (void) this; // loplugin:staticmethods
5651 #endif
5654 void ToolBox::SetToolbarLayoutMode( ToolBoxLayoutMode eLayout )
5656 if ( meLayoutMode != eLayout )
5657 meLayoutMode = eLayout;
5660 void ToolBox::SetToolBoxTextPosition( ToolBoxTextPosition ePosition )
5662 meTextPosition = ePosition;
5665 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */