Bug Summary

File:home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx
Warning:line 2269, column 17
Value stored to 'nX' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name toolbox.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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/mnemonic.hxx>
28#include <vcl/gradient.hxx>
29#include <vcl/layout.hxx>
30#include <vcl/menu.hxx>
31#include <vcl/settings.hxx>
32#include <vclstatuslistener.hxx>
33#include <vcl/ptrstyle.hxx>
34#include <bitmaps.hlst>
35
36#include <tools/poly.hxx>
37#include <svl/imageitm.hxx>
38#include <sal/log.hxx>
39#include <osl/diagnose.h>
40
41#include <svdata.hxx>
42#include <window.h>
43#include <toolbox.h>
44#include <spin.hxx>
45#if defined(_WIN32)
46#include <svsys.h>
47#endif
48
49#include <cstdlib>
50#include <vector>
51#include <math.h>
52
53
54#define SMALLBUTTON_HSIZE7 7
55#define SMALLBUTTON_VSIZE7 7
56
57#define SMALLBUTTON_OFF_NORMAL_X3 3
58#define SMALLBUTTON_OFF_NORMAL_Y3 3
59
60#define TB_TEXTOFFSET2 2
61#define TB_IMAGETEXTOFFSET3 3
62#define TB_LINESPACING3 3
63#define TB_SPIN_SIZE14 14
64#define TB_SPIN_OFFSET2 2
65#define TB_BORDER_OFFSET14 4
66#define TB_BORDER_OFFSET22 2
67#define TB_MAXLINES5 5
68#define TB_MAXNOSCROLL32765 32765
69
70#define TB_DRAGWIDTH8 8 // the default width of the drag grip
71
72#define TB_CALCMODE_HORZ1 1
73#define TB_CALCMODE_VERT2 2
74#define TB_CALCMODE_FLOAT3 3
75
76#define TB_WBLINESIZING(WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL) (WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL)
77
78#define DOCK_LINEHSIZE(sal_uInt16(0x0001)) (sal_uInt16(0x0001))
79#define DOCK_LINEVSIZE(sal_uInt16(0x0002)) (sal_uInt16(0x0002))
80#define DOCK_LINERIGHT(sal_uInt16(0x1000)) (sal_uInt16(0x1000))
81#define DOCK_LINEBOTTOM(sal_uInt16(0x2000)) (sal_uInt16(0x2000))
82#define DOCK_LINELEFT(sal_uInt16(0x4000)) (sal_uInt16(0x4000))
83#define DOCK_LINETOP(sal_uInt16(0x8000)) (sal_uInt16(0x8000))
84#define DOCK_LINEOFFSET3 3
85
86class ImplTBDragMgr
87{
88private:
89 VclPtr<ToolBox> mpDragBox;
90 Point maMouseOff;
91 tools::Rectangle maRect;
92 tools::Rectangle maStartRect;
93 Accelerator maAccel;
94 sal_uInt16 mnLineMode;
95 ToolBox::ImplToolItems::size_type mnStartLines;
96
97 ImplTBDragMgr(const ImplTBDragMgr&) = delete;
98 ImplTBDragMgr& operator=(const ImplTBDragMgr&) = delete;
99
100public:
101 ImplTBDragMgr();
102
103 void StartDragging( ToolBox* pDragBox, const Point& rPos, const tools::Rectangle& rRect, sal_uInt16 nLineMode );
104 void Dragging( const Point& rPos );
105 void EndDragging( bool bOK = true );
106 DECL_LINK( SelectHdl, Accelerator&, void )static void LinkStubSelectHdl(void *, Accelerator&); void
SelectHdl(Accelerator&)
;
107};
108
109
110static ImplTBDragMgr* ImplGetTBDragMgr()
111{
112 ImplSVData* pSVData = ImplGetSVData();
113 if ( !pSVData->maCtrlData.mpTBDragMgr )
114 pSVData->maCtrlData.mpTBDragMgr = new ImplTBDragMgr;
115 return pSVData->maCtrlData.mpTBDragMgr;
116}
117
118int ToolBox::ImplGetDragWidth( const vcl::RenderContext& rRenderContext, bool bHorz )
119{
120 int nWidth = TB_DRAGWIDTH8;
121 if( rRenderContext.IsNativeControlSupported( ControlType::Toolbar, ControlPart::Entire ) )
122 {
123
124 ImplControlValue aControlValue;
125 tools::Rectangle aContent, aBound;
126 tools::Rectangle aArea( Point(), rRenderContext.GetOutputSizePixel() );
127
128 if ( rRenderContext.GetNativeControlRegion(ControlType::Toolbar,
129 bHorz ? ControlPart::ThumbVert : ControlPart::ThumbHorz,
130 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
131 {
132 nWidth = bHorz ? aContent.GetWidth() : aContent.GetHeight();
133 }
134 }
135
136 // increase the hit area of the drag handle according to DPI scale factor
137 nWidth *= rRenderContext.GetDPIScaleFactor();
138
139 return nWidth;
140}
141
142int ToolBox::ImplGetDragWidth() const
143{
144 return ToolBox::ImplGetDragWidth( *this, mbHorz );
145}
146
147static ButtonType determineButtonType( ImplToolItem const * pItem, ButtonType defaultType )
148{
149 ButtonType tmpButtonType = defaultType;
150 ToolBoxItemBits nBits = pItem->mnBits & ( ToolBoxItemBits::TEXT_ONLY | ToolBoxItemBits::ICON_ONLY );
151 if ( nBits != ToolBoxItemBits::NONE ) // item has custom setting
152 {
153 tmpButtonType = ButtonType::SYMBOLTEXT;
154 if ( nBits == ToolBoxItemBits::TEXT_ONLY )
155 tmpButtonType = ButtonType::TEXT;
156 else if ( nBits == ToolBoxItemBits::ICON_ONLY )
157 tmpButtonType = ButtonType::SYMBOLONLY;
158 }
159 return tmpButtonType;
160}
161
162void ToolBox::ImplUpdateDragArea() const
163{
164 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
165 if( pWrapper )
166 {
167 if ( ImplIsFloatingMode() || pWrapper->IsLocked() )
168 pWrapper->SetDragArea( tools::Rectangle() );
169 else
170 {
171 if( meAlign == WindowAlign::Top || meAlign == WindowAlign::Bottom )
172 pWrapper->SetDragArea( tools::Rectangle( 0, 0, ImplGetDragWidth(), GetOutputSizePixel().Height() ) );
173 else
174 pWrapper->SetDragArea( tools::Rectangle( 0, 0, GetOutputSizePixel().Width(), ImplGetDragWidth() ) );
175 }
176 }
177}
178
179void ToolBox::ImplCalcBorder( WindowAlign eAlign, long& rLeft, long& rTop,
180 long& rRight, long& rBottom ) const
181{
182 if( ImplIsFloatingMode() || !(mnWinStyle & WB_BORDER) )
183 {
184 // no border in floating mode
185 rLeft = rTop = rRight = rBottom = 0;
186 return;
187 }
188
189 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
190
191 // reserve DragArea only for dockable toolbars
192 int dragwidth = ( pWrapper && !pWrapper->IsLocked() ) ? ImplGetDragWidth() : 0;
193
194 // no shadow border for dockable toolbars and toolbars with WB_NOSHADOW bit set, e.g. Calc's formulabar
195 int borderwidth = ( pWrapper || mnWinStyle & WB_NOSHADOW ) ? 0 : 2;
196
197 if ( eAlign == WindowAlign::Top )
198 {
199 rLeft = borderwidth+dragwidth;
200 rTop = borderwidth;
201 rRight = borderwidth;
202 rBottom = 0;
203 }
204 else if ( eAlign == WindowAlign::Left )
205 {
206 rLeft = borderwidth;
207 rTop = borderwidth+dragwidth;
208 rRight = 0;
209 rBottom = borderwidth;
210 }
211 else if ( eAlign == WindowAlign::Bottom )
212 {
213 rLeft = borderwidth+dragwidth;
214 rTop = 0;
215 rRight = borderwidth;
216 rBottom = borderwidth;
217 }
218 else
219 {
220 rLeft = 0;
221 rTop = borderwidth+dragwidth;
222 rRight = borderwidth;
223 rBottom = borderwidth;
224 }
225}
226
227void ToolBox::ImplCheckUpdate()
228{
229 // remove any pending invalidates to avoid
230 // have them triggered when paint is locked (see mpData->mbIsPaintLocked)
231 // which would result in erasing the background only and not painting any items
232 // this must not be done when we're already in Paint()
233
234 // this is only required for transparent toolbars (see ImplDrawTransparentBackground() )
235 if( !IsBackground() && HasPaintEvent() && !IsInPaint() )
236 PaintImmediately();
237}
238
239void ToolBox::ImplDrawGrip(vcl::RenderContext& rRenderContext,
240 const tools::Rectangle &aDragArea, int nDragWidth, WindowAlign eAlign, bool bHorz)
241{
242 bool bNativeOk = false;
243 const ControlPart ePart = bHorz ? ControlPart::ThumbVert : ControlPart::ThumbHorz;
244 const Size aSz( rRenderContext.GetOutputSizePixel() );
245 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ePart))
246 {
247 ToolbarValue aToolbarValue;
248 aToolbarValue.maGripRect = aDragArea;
249
250 tools::Rectangle aCtrlRegion(Point(), aSz);
251
252 bNativeOk = rRenderContext.DrawNativeControl( ControlType::Toolbar, ePart,
253 aCtrlRegion, ControlState::ENABLED, aToolbarValue, OUString() );
254 }
255
256 if( bNativeOk )
257 return;
258
259 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
260 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
261 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
262
263 float fScaleFactor = rRenderContext.GetDPIScaleFactor();
264
265 if (eAlign == WindowAlign::Top || eAlign == WindowAlign::Bottom)
266 {
267 int height = static_cast<int>(0.6 * aSz.Height() + 0.5);
268 int i = (aSz.Height() - height) / 2;
269 height += i;
270 while (i <= height)
271 {
272 int x = nDragWidth / 2;
273 rRenderContext.DrawEllipse(tools::Rectangle(Point(x, i), Size(2 * fScaleFactor, 2 * fScaleFactor)));
274 i += 4 * fScaleFactor;
275 }
276 }
277 else
278 {
279 int width = static_cast<int>(0.6 * aSz.Width() + 0.5);
280 int i = (aSz.Width() - width) / 2;
281 width += i;
282 while (i <= width)
283 {
284 int y = nDragWidth / 2;
285 rRenderContext.DrawEllipse(tools::Rectangle(Point(i, y), Size(2 * fScaleFactor, 2 * fScaleFactor)));
286 i += 4 * fScaleFactor;
287 }
288 }
289}
290
291void ToolBox::ImplDrawGrip(vcl::RenderContext& rRenderContext)
292{
293 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
294 if( pWrapper && !pWrapper->GetDragArea().IsEmpty() )
295 {
296 // execute pending paint requests
297 ImplCheckUpdate();
298 ImplDrawGrip( rRenderContext, pWrapper->GetDragArea(),
299 ImplGetDragWidth(), meAlign, mbHorz );
300 }
301}
302
303void ToolBox::ImplDrawGradientBackground(vcl::RenderContext& rRenderContext)
304{
305 // draw a nice gradient
306
307 Color startCol, endCol;
308 const StyleSettings rSettings = rRenderContext.GetSettings().GetStyleSettings();
309
310 startCol = rSettings.GetFaceGradientColor();
311 endCol = rSettings.GetFaceColor();
312 if (rSettings.GetHighContrastMode())
313 // no 'extreme' gradient when high contrast
314 startCol = endCol;
315
316 Gradient g;
317 g.SetAngle(mbHorz ? 0 : 900);
318 g.SetStyle(GradientStyle::Linear);
319
320 g.SetStartColor(startCol);
321 g.SetEndColor(endCol);
322
323 bool bLineColor = rRenderContext.IsLineColor();
324 Color aOldCol = rRenderContext.GetLineColor();
325 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
326
327 Size aFullSz(GetOutputSizePixel());
328 Size aLineSz(aFullSz);
329
330 // use the linesize only when floating
331 // full window height is used when docked (single line)
332 if (ImplIsFloatingMode())
333 {
334 long nLineSize;
335 if (mbHorz)
336 {
337 nLineSize = mnMaxItemHeight;
338 if (mnWinHeight > mnMaxItemHeight)
339 nLineSize = mnWinHeight;
340
341 aLineSz.setHeight( nLineSize );
342 }
343 else
344 {
345 nLineSize = mnMaxItemWidth;
346 aLineSz.setWidth( nLineSize );
347 }
348 }
349
350 long nLeft, nTop, nRight, nBottom;
351 ImplCalcBorder(meAlign, nLeft, nTop, nRight, nBottom);
352
353 Size aTopLineSz(aLineSz);
354 Size aBottomLineSz(aLineSz);
355
356 if (mnWinStyle & WB_BORDER)
357 {
358 if (mbHorz)
359 {
360 aTopLineSz.AdjustHeight(TB_BORDER_OFFSET22 + nTop );
361 aBottomLineSz.AdjustHeight(TB_BORDER_OFFSET22 + nBottom );
362
363 if (mnCurLines == 1)
364 aTopLineSz.AdjustHeight(TB_BORDER_OFFSET22 + nBottom );
365 }
366 else
367 {
368 aTopLineSz.AdjustWidth(TB_BORDER_OFFSET14 + nLeft );
369 aBottomLineSz.AdjustWidth(TB_BORDER_OFFSET14 + nRight );
370
371 if (mnCurLines == 1)
372 aTopLineSz.AdjustWidth(TB_BORDER_OFFSET14 + nLeft );
373 }
374 }
375
376 if (mbLineSpacing)
377 {
378 if (mbHorz)
379 {
380 aLineSz.AdjustHeight(TB_LINESPACING3 );
381 if (mnCurLines > 1)
382 aTopLineSz.AdjustHeight(TB_LINESPACING3 );
383 }
384 else
385 {
386 aLineSz.AdjustWidth(TB_LINESPACING3 );
387 if (mnCurLines > 1)
388 aTopLineSz.AdjustWidth(TB_LINESPACING3 );
389 }
390 }
391
392 if (mbHorz)
393 {
394 long y = 0;
395
396 rRenderContext.DrawGradient(tools::Rectangle(0, y, aTopLineSz.Width(), y + aTopLineSz.Height()), g);
397 y += aTopLineSz.Height();
398
399 while (y < (mnDY - aBottomLineSz.Height()))
400 {
401 rRenderContext.DrawGradient(tools::Rectangle(0, y, aLineSz.Width(), y + aLineSz.Height()), g);
402 y += aLineSz.Height();
403 }
404
405 rRenderContext.DrawGradient(tools::Rectangle(0, y, aBottomLineSz.Width(), y + aBottomLineSz.Height()), g);
406 }
407 else
408 {
409 long x = 0;
410
411 rRenderContext.DrawGradient(tools::Rectangle(x, 0, x + aTopLineSz.Width(), aTopLineSz.Height()), g);
412 x += aTopLineSz.Width();
413
414 while (x < (mnDX - aBottomLineSz.Width()))
415 {
416 rRenderContext.DrawGradient(tools::Rectangle(x, 0, x + aLineSz.Width(), aLineSz.Height()), g);
417 x += aLineSz.Width();
418 }
419
420 rRenderContext.DrawGradient(tools::Rectangle( x, 0, x + aBottomLineSz.Width(), aBottomLineSz.Height()), g);
421 }
422
423 if( bLineColor )
424 rRenderContext.SetLineColor( aOldCol );
425
426}
427
428bool ToolBox::ImplDrawNativeBackground(vcl::RenderContext& rRenderContext)
429{
430 // use NWF
431 tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
432
433 return rRenderContext.DrawNativeControl( ControlType::Toolbar, mbHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert,
434 aCtrlRegion, ControlState::ENABLED, ImplControlValue(), OUString() );
435}
436
437void ToolBox::ImplDrawTransparentBackground(const vcl::Region &rRegion)
438{
439 // just invalidate to trigger paint of the parent
440 const bool bOldPaintLock = mpData->mbIsPaintLocked;
441 mpData->mbIsPaintLocked = true;
442
443 // send an invalidate to the first opaque parent and invalidate the whole hierarchy from there (noclipchildren)
444 Invalidate(rRegion, InvalidateFlags::Update | InvalidateFlags::NoClipChildren);
445
446 mpData->mbIsPaintLocked = bOldPaintLock;
447}
448
449void ToolBox::ImplDrawConstantBackground(vcl::RenderContext& rRenderContext, const vcl::Region &rRegion, bool bIsInPopupMode)
450{
451 // draw a constant color
452 if (!bIsInPopupMode)
453 {
454 // default background
455 rRenderContext.Erase(rRegion.GetBoundRect());
456 }
457 else
458 {
459 // use different color in popupmode
460 const StyleSettings rSettings = rRenderContext.GetSettings().GetStyleSettings();
461 Wallpaper aWallpaper(rSettings.GetFaceGradientColor());
462 rRenderContext.DrawWallpaper(rRegion.GetBoundRect(), aWallpaper);
463 }
464}
465
466void ToolBox::ImplDrawBackground(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
467{
468 // execute pending paint requests
469 ImplCheckUpdate();
470
471 ImplDockingWindowWrapper* pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
472 bool bIsInPopupMode = ImplIsInPopupMode();
473
474 vcl::Region aPaintRegion(rRect);
475
476 // make sure we do not invalidate/erase too much
477 if (IsInPaint())
478 aPaintRegion.Intersect(GetActiveClipRegion());
479
480 rRenderContext.Push(PushFlags::CLIPREGION);
481 rRenderContext.IntersectClipRegion( aPaintRegion );
482
483 if (!pWrapper)
484 {
485 // no gradient for ordinary toolbars (not dockable)
486 if( !IsBackground() && !IsInPaint() )
487 ImplDrawTransparentBackground(aPaintRegion);
488 else
489 ImplDrawConstantBackground(rRenderContext, aPaintRegion, bIsInPopupMode);
490 }
491 else
492 {
493 // toolbars known to the dockingmanager will be drawn using NWF or a gradient
494 // docked toolbars are transparent and NWF is already used in the docking area which is their common background
495 // so NWF is used here for floating toolbars only
496 bool bNativeOk = false;
497 if( ImplIsFloatingMode() && rRenderContext.IsNativeControlSupported( ControlType::Toolbar, ControlPart::Entire) )
498 bNativeOk = ImplDrawNativeBackground(rRenderContext);
499 if (!bNativeOk)
500 {
501 const StyleSettings rSetting = Application::GetSettings().GetStyleSettings();
502 const bool isHeader = GetAlign() == WindowAlign::Top && !rSetting.GetPersonaHeader().IsEmpty();
503 const bool isFooter = GetAlign() == WindowAlign::Bottom && !rSetting.GetPersonaFooter().IsEmpty();
504 if (!IsBackground() || isHeader || isFooter)
505 {
506 if (!IsInPaint())
507 ImplDrawTransparentBackground(aPaintRegion);
508 }
509 else
510 ImplDrawGradientBackground(rRenderContext);
511 }
512 }
513
514 // restore clip region
515 rRenderContext.Pop();
516}
517
518void ToolBox::ImplErase(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect, bool bHighlight, bool bHasOpenPopup)
519{
520 // the background of non NWF buttons is painted in a constant color
521 // to have the same highlight color (transparency in DrawSelectionBackground())
522 // items with open popups will also painted using a constant color
523 if (!mpData->mbNativeButtons &&
524 (bHighlight || !(GetStyle() & WB_3DLOOK)))
525 {
526 if (GetStyle() & WB_3DLOOK)
527 {
528 rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
529 rRenderContext.SetLineColor();
530 if (bHasOpenPopup)
531 // choose the same color as the popup will use
532 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetFaceGradientColor());
533 else
534 rRenderContext.SetFillColor(COL_WHITE);
535
536 rRenderContext.DrawRect(rRect);
537 rRenderContext.Pop();
538 }
539 else
540 ImplDrawBackground(rRenderContext, rRect);
541 }
542 else
543 ImplDrawBackground(rRenderContext, rRect);
544}
545
546void ToolBox::ImplDrawBorder(vcl::RenderContext& rRenderContext)
547{
548 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
549 long nDX = mnDX;
550 long nDY = mnDY;
551
552 ImplDockingWindowWrapper* pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper(this);
553
554 // draw borders for ordinary toolbars only (not dockable), do not draw borders for toolbars with WB_NOSHADOW bit set,
555 // e.g. Calc's formulabar
556
557 if( pWrapper || mnWinStyle & WB_NOSHADOW )
558 return;
559
560 if (meAlign == WindowAlign::Bottom)
561 {
562 // draw bottom border
563 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
564 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
565 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
566 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
567 }
568 else
569 {
570 // draw top border
571 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
572 rRenderContext.DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) );
573 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
574 rRenderContext.DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) );
575
576 if (meAlign == WindowAlign::Left || meAlign == WindowAlign::Right)
577 {
578 if (meAlign == WindowAlign::Left)
579 {
580 // draw left-bottom border
581 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
582 rRenderContext.DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) );
583 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) );
584 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
585 rRenderContext.DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) );
586 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
587 }
588 else
589 {
590 // draw right-bottom border
591 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
592 rRenderContext.DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) );
593 rRenderContext.DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) );
594 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
595 rRenderContext.DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
596 rRenderContext.DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) );
597 }
598 }
599 }
600
601 if ( meAlign == WindowAlign::Bottom || meAlign == WindowAlign::Top )
602 {
603 // draw right border
604 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
605 rRenderContext.DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) );
606 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
607 rRenderContext.DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) );
608 }
609}
610
611static bool ImplIsFixedControl( const ImplToolItem *pItem )
612{
613 return ( pItem->mpWindow &&
614 (pItem->mbNonInteractiveWindow ||
615 pItem->mpWindow->GetType() == WindowType::FIXEDTEXT ||
616 pItem->mpWindow->GetType() == WindowType::FIXEDLINE ||
617 pItem->mpWindow->GetType() == WindowType::GROUPBOX) );
618}
619
620const ImplToolItem *ToolBox::ImplGetFirstClippedItem() const
621{
622 for (auto & item : mpData->m_aItems)
623 {
624 if( item.IsClipped() )
625 return &item;
626 }
627 return nullptr;
628}
629
630Size ToolBox::ImplCalcSize( ImplToolItems::size_type nCalcLines, sal_uInt16 nCalcMode )
631{
632 long nMax;
633 long nLeft = 0;
634 long nTop = 0;
635 long nRight = 0;
636 long nBottom = 0;
637 Size aSize;
638 WindowAlign eOldAlign = meAlign;
639 bool bOldHorz = mbHorz;
640 bool bOldAssumeDocked = mpData->mbAssumeDocked;
641 bool bOldAssumeFloating = mpData->mbAssumeFloating;
642
643 if ( nCalcMode )
644 {
645 bool bOldFloatingMode = ImplIsFloatingMode();
646
647 mpData->mbAssumeDocked = false;
648 mpData->mbAssumeFloating = false;
649
650 if ( nCalcMode == TB_CALCMODE_HORZ1 )
651 {
652 mpData->mbAssumeDocked = true; // force non-floating mode during calculation
653 ImplCalcBorder( WindowAlign::Top, nLeft, nTop, nRight, nBottom );
654 mbHorz = true;
655 if ( mbHorz != bOldHorz )
656 meAlign = WindowAlign::Top;
657 }
658 else if ( nCalcMode == TB_CALCMODE_VERT2 )
659 {
660 mpData->mbAssumeDocked = true; // force non-floating mode during calculation
661 ImplCalcBorder( WindowAlign::Left, nLeft, nTop, nRight, nBottom );
662 mbHorz = false;
663 if ( mbHorz != bOldHorz )
664 meAlign = WindowAlign::Left;
665 }
666 else if ( nCalcMode == TB_CALCMODE_FLOAT3 )
667 {
668 mpData->mbAssumeFloating = true; // force non-floating mode during calculation
669 nLeft = nTop = nRight = nBottom = 0;
670 mbHorz = true;
671 if ( mbHorz != bOldHorz )
672 meAlign = WindowAlign::Top;
673 }
674
675 if ( (meAlign != eOldAlign) || (mbHorz != bOldHorz) ||
676 (ImplIsFloatingMode() != bOldFloatingMode ) )
677 mbCalc = true;
678 }
679 else
680 ImplCalcBorder( meAlign, nLeft, nTop, nRight, nBottom );
681
682 ImplCalcItem();
683
684 if( !nCalcMode && ImplIsFloatingMode() )
685 {
686 aSize = ImplCalcFloatSize( nCalcLines );
687 }
688 else
689 {
690 if ( mbHorz )
691 {
692 if ( mnWinHeight > mnMaxItemHeight )
693 aSize.setHeight( nCalcLines * mnWinHeight );
694 else
695 aSize.setHeight( nCalcLines * mnMaxItemHeight );
696
697 if ( mbLineSpacing )
698 aSize.AdjustHeight((nCalcLines-1)*TB_LINESPACING3 );
699
700 if ( mnWinStyle & WB_BORDER )
701 aSize.AdjustHeight((TB_BORDER_OFFSET22*2) + nTop + nBottom );
702
703 nMax = 0;
704 ImplCalcBreaks( TB_MAXNOSCROLL32765, &nMax, mbHorz );
705 if ( nMax )
706 aSize.AdjustWidth(nMax );
707
708 if ( mnWinStyle & WB_BORDER )
709 aSize.AdjustWidth((TB_BORDER_OFFSET14*2) + nLeft + nRight );
710 }
711 else
712 {
713 aSize.setWidth( nCalcLines * mnMaxItemWidth );
714
715 if ( mbLineSpacing )
716 aSize.AdjustWidth((nCalcLines-1)*TB_LINESPACING3 );
717
718 if ( mnWinStyle & WB_BORDER )
719 aSize.AdjustWidth((TB_BORDER_OFFSET22*2) + nLeft + nRight );
720
721 nMax = 0;
722 ImplCalcBreaks( TB_MAXNOSCROLL32765, &nMax, mbHorz );
723 if ( nMax )
724 aSize.AdjustHeight(nMax );
725
726 if ( mnWinStyle & WB_BORDER )
727 aSize.AdjustHeight((TB_BORDER_OFFSET14*2) + nTop + nBottom );
728 }
729 }
730 // restore previous values
731 if ( nCalcMode )
732 {
733 mpData->mbAssumeDocked = bOldAssumeDocked;
734 mpData->mbAssumeFloating = bOldAssumeFloating;
735 if ( (meAlign != eOldAlign) || (mbHorz != bOldHorz) )
736 {
737 meAlign = eOldAlign;
738 mbHorz = bOldHorz;
739 mbCalc = true;
740 }
741 }
742
743 return aSize;
744}
745
746void ToolBox::ImplCalcFloatSizes()
747{
748 if ( !maFloatSizes.empty() )
749 return;
750
751 // calculate the minimal size, i.e. where the biggest item just fits
752 long nCalcSize = 0;
753
754 for (auto const& item : mpData->m_aItems)
755 {
756 if ( item.mbVisible )
757 {
758 if ( item.mpWindow )
759 {
760 long nTempSize = item.mpWindow->GetSizePixel().Width();
761 if ( nTempSize > nCalcSize )
762 nCalcSize = nTempSize;
763 }
764 else
765 {
766 if( item.maItemSize.Width() > nCalcSize )
767 nCalcSize = item.maItemSize.Width();
768 }
769 }
770 }
771
772 // calc an upper bound for ImplCalcBreaks below
773 long upperBoundWidth = nCalcSize * mpData->m_aItems.size();
774
775 ImplToolItems::size_type nLines;
776 ImplToolItems::size_type nCalcLines;
777 ImplToolItems::size_type nTempLines;
778 long nMaxLineWidth;
779 nCalcLines = ImplCalcBreaks( nCalcSize, &nMaxLineWidth, true );
780
781 maFloatSizes.reserve( nCalcLines );
782
783 nTempLines = nLines = nCalcLines;
784 while ( nLines )
785 {
786 long nHeight = ImplCalcSize( nTempLines, TB_CALCMODE_FLOAT3 ).Height();
787
788 ImplToolSize aSize;
789 aSize.mnWidth = nMaxLineWidth+(TB_BORDER_OFFSET14*2);
790 aSize.mnHeight = nHeight;
791 aSize.mnLines = nTempLines;
792 maFloatSizes.push_back( aSize );
793 nLines--;
794 if ( nLines )
795 {
796 do
797 {
798 nCalcSize += mnMaxItemWidth;
799 nTempLines = ImplCalcBreaks( nCalcSize, &nMaxLineWidth, true );
800 }
801 while ((nCalcSize < upperBoundWidth) && (nLines < nTempLines)); // implies nTempLines>1
802 if ( nTempLines < nLines )
803 nLines = nTempLines;
804 }
805 }
806}
807
808Size ToolBox::ImplCalcFloatSize( ImplToolItems::size_type& rLines )
809{
810 ImplCalcFloatSizes();
811
812 if ( !rLines )
813 {
814 rLines = mnFloatLines;
815 if ( !rLines )
816 rLines = mnLines;
817 }
818
819 sal_uInt16 i = 0;
820 while ( i + 1u < maFloatSizes.size() && rLines < maFloatSizes[i].mnLines )
821 {
822 i++;
823 }
824
825 Size aSize( maFloatSizes[i].mnWidth, maFloatSizes[i].mnHeight );
826 rLines = maFloatSizes[i].mnLines;
827
828 return aSize;
829}
830
831void ToolBox::ImplCalcMinMaxFloatSize( Size& rMinSize, Size& rMaxSize )
832{
833 ImplCalcFloatSizes();
834
835 sal_uInt16 i = 0;
836 rMinSize = Size( maFloatSizes[i].mnWidth, maFloatSizes[i].mnHeight );
837 rMaxSize = Size( maFloatSizes[i].mnWidth, maFloatSizes[i].mnHeight );
838 while ( ++i < maFloatSizes.size() )
839 {
840 if( maFloatSizes[i].mnWidth < rMinSize.Width() )
841 rMinSize.setWidth( maFloatSizes[i].mnWidth );
842 if( maFloatSizes[i].mnHeight < rMinSize.Height() )
843 rMinSize.setHeight( maFloatSizes[i].mnHeight );
844
845 if( maFloatSizes[i].mnWidth > rMaxSize.Width() )
846 rMaxSize.setWidth( maFloatSizes[i].mnWidth );
847 if( maFloatSizes[i].mnHeight > rMaxSize.Height() )
848 rMaxSize.setHeight( maFloatSizes[i].mnHeight );
849 }
850}
851
852void ToolBox::ImplSetMinMaxFloatSize()
853{
854 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
855 Size aMinSize, aMaxSize;
856 ImplCalcMinMaxFloatSize( aMinSize, aMaxSize );
857 if( pWrapper )
858 {
859 pWrapper->SetMinOutputSizePixel( aMinSize );
860 pWrapper->SetMaxOutputSizePixel( aMaxSize );
861 pWrapper->ShowTitleButton( TitleButton::Menu, bool( GetMenuType() & ToolBoxMenuType::Customize) );
862 }
863 else
864 {
865 // TODO: change SetMinOutputSizePixel to be not inline
866 SetMinOutputSizePixel( aMinSize );
867 SetMaxOutputSizePixel( aMaxSize );
868 }
869}
870
871ToolBox::ImplToolItems::size_type ToolBox::ImplCalcLines( long nToolSize ) const
872{
873 long nLineHeight;
874
875 if ( mbHorz )
876 {
877 if ( mnWinHeight > mnMaxItemHeight )
878 nLineHeight = mnWinHeight;
879 else
880 nLineHeight = mnMaxItemHeight;
881 }
882 else
883 nLineHeight = mnMaxItemWidth;
884
885 if ( mnWinStyle & WB_BORDER )
886 nToolSize -= TB_BORDER_OFFSET22*2;
887
888 if ( mbLineSpacing )
889 {
890 nLineHeight += TB_LINESPACING3;
891 nToolSize += TB_LINESPACING3;
892 }
893
894 // #i91917# always report at least one line
895 long nLines = nToolSize/nLineHeight;
896 if( nLines < 1 )
897 nLines = 1;
898
899 return nLines;
900}
901
902sal_uInt16 ToolBox::ImplTestLineSize( const Point& rPos ) const
903{
904 if ( !ImplIsFloatingMode() &&
905 (!mbScroll || (mnLines > 1) || (mnCurLines > mnVisLines)) )
906 {
907 WindowAlign eAlign = GetAlign();
908
909 if ( eAlign == WindowAlign::Left )
910 {
911 if ( rPos.X() > mnDX-DOCK_LINEOFFSET3 )
912 return DOCK_LINEHSIZE(sal_uInt16(0x0001)) | DOCK_LINERIGHT(sal_uInt16(0x1000));
913 }
914 else if ( eAlign == WindowAlign::Top )
915 {
916 if ( rPos.Y() > mnDY-DOCK_LINEOFFSET3 )
917 return DOCK_LINEVSIZE(sal_uInt16(0x0002)) | DOCK_LINEBOTTOM(sal_uInt16(0x2000));
918 }
919 else if ( eAlign == WindowAlign::Right )
920 {
921 if ( rPos.X() < DOCK_LINEOFFSET3 )
922 return DOCK_LINEHSIZE(sal_uInt16(0x0001)) | DOCK_LINELEFT(sal_uInt16(0x4000));
923 }
924 else if ( eAlign == WindowAlign::Bottom )
925 {
926 if ( rPos.Y() < DOCK_LINEOFFSET3 )
927 return DOCK_LINEVSIZE(sal_uInt16(0x0002)) | DOCK_LINETOP(sal_uInt16(0x8000));
928 }
929 }
930
931 return 0;
932}
933
934void ToolBox::ImplLineSizing( const Point& rPos, tools::Rectangle& rRect, sal_uInt16 nLineMode )
935{
936 bool bHorz;
937 long nOneLineSize;
938 long nCurSize;
939 long nMaxSize;
940 long nSize;
941 Size aSize;
942
943 if ( nLineMode & DOCK_LINERIGHT(sal_uInt16(0x1000)) )
944 {
945 nCurSize = rPos.X() - rRect.Left();
946 bHorz = false;
947 }
948 else if ( nLineMode & DOCK_LINEBOTTOM(sal_uInt16(0x2000)) )
949 {
950 nCurSize = rPos.Y() - rRect.Top();
951 bHorz = true;
952 }
953 else if ( nLineMode & DOCK_LINELEFT(sal_uInt16(0x4000)) )
954 {
955 nCurSize = rRect.Right() - rPos.X();
956 bHorz = false;
957 }
958 else if ( nLineMode & DOCK_LINETOP(sal_uInt16(0x8000)) )
959 {
960 nCurSize = rRect.Bottom() - rPos.Y();
961 bHorz = true;
962 }
963 else {
964 OSL_FAIL( "ImplLineSizing: Trailing else" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "964" ": "), "%s", "ImplLineSizing: Trailing else"); } }
while (false)
;
965 nCurSize = 0;
966 bHorz = false;
967 }
968
969 Size aWinSize = GetSizePixel();
970 ImplToolItems::size_type nMaxLines = std::max(mnLines, mnCurLines);
971 if ( nMaxLines > TB_MAXLINES5 )
972 nMaxLines = TB_MAXLINES5;
973 if ( bHorz )
974 {
975 nOneLineSize = ImplCalcSize( 1 ).Height();
976 nMaxSize = - 20;
977 if ( nMaxSize < aWinSize.Height() )
978 nMaxSize = aWinSize.Height();
979 }
980 else
981 {
982 nOneLineSize = ImplCalcSize( 1 ).Width();
983 nMaxSize = - 20;
984 if ( nMaxSize < aWinSize.Width() )
985 nMaxSize = aWinSize.Width();
986 }
987
988 ImplToolItems::size_type i = 1;
989 if ( nCurSize <= nOneLineSize )
990 nSize = nOneLineSize;
991 else
992 {
993 nSize = 0;
994 while ( (nSize < nCurSize) && (i < nMaxLines) )
995 {
996 i++;
997 aSize = ImplCalcSize( i );
998 if ( bHorz )
999 nSize = aSize.Height();
1000 else
1001 nSize = aSize.Width();
1002 if ( nSize > nMaxSize )
1003 {
1004 i--;
1005 aSize = ImplCalcSize( i );
1006 if ( bHorz )
1007 nSize = aSize.Height();
1008 else
1009 nSize = aSize.Width();
1010 break;
1011 }
1012 }
1013 }
1014
1015 if ( nLineMode & DOCK_LINERIGHT(sal_uInt16(0x1000)) )
1016 rRect.SetRight( rRect.Left()+nSize-1 );
1017 else if ( nLineMode & DOCK_LINEBOTTOM(sal_uInt16(0x2000)) )
1018 rRect.SetBottom( rRect.Top()+nSize-1 );
1019 else if ( nLineMode & DOCK_LINELEFT(sal_uInt16(0x4000)) )
1020 rRect.SetLeft( rRect.Right()-nSize );
1021 else
1022 rRect.SetTop( rRect.Bottom()-nSize );
1023
1024 mnDockLines = i;
1025}
1026
1027ImplTBDragMgr::ImplTBDragMgr()
1028 : mpDragBox(nullptr)
1029 , mnLineMode(0)
1030 , mnStartLines(0)
1031{
1032 maAccel.InsertItem( KEY_RETURN, vcl::KeyCode( KEY_RETURN ) );
1033 maAccel.InsertItem( KEY_ESCAPE, vcl::KeyCode( KEY_ESCAPE ) );
1034 maAccel.SetSelectHdl( LINK( this, ImplTBDragMgr, SelectHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImplTBDragMgr
*>(this), &ImplTBDragMgr::LinkStubSelectHdl)
);
1035}
1036
1037void ImplTBDragMgr::StartDragging( ToolBox* pToolBox,
1038 const Point& rPos, const tools::Rectangle& rRect,
1039 sal_uInt16 nDragLineMode )
1040{
1041 mpDragBox = pToolBox;
1042 pToolBox->CaptureMouse();
1043 pToolBox->mbDragging = true;
1044 Application::InsertAccel( &maAccel );
1045
1046 mnLineMode = nDragLineMode;
1047 mnStartLines = pToolBox->mnDockLines;
1048
1049 // calculate MouseOffset
1050 maMouseOff.setX( rRect.Left() - rPos.X() );
1051 maMouseOff.setY( rRect.Top() - rPos.Y() );
1052 maRect = rRect;
1053 maStartRect = rRect;
1054 pToolBox->ShowTracking( maRect );
1055}
1056
1057void ImplTBDragMgr::Dragging( const Point& rPos )
1058{
1059 mpDragBox->ImplLineSizing( rPos, maRect, mnLineMode );
1060 Point aOff = mpDragBox->OutputToScreenPixel( Point() );
1061 maRect.Move( aOff.X(), aOff.Y() );
1062 mpDragBox->Docking( rPos, maRect );
1063 maRect.Move( -aOff.X(), -aOff.Y() );
1064 mpDragBox->ShowTracking( maRect );
1065}
1066
1067void ImplTBDragMgr::EndDragging( bool bOK )
1068{
1069 mpDragBox->HideTracking();
1070 if (mpDragBox->IsMouseCaptured())
1071 mpDragBox->ReleaseMouse();
1072 mpDragBox->mbDragging = false;
1073 Application::RemoveAccel( &maAccel );
1074
1075 if ( !bOK )
1076 {
1077 mpDragBox->mnDockLines = mnStartLines;
1078 mpDragBox->EndDocking( maStartRect, false );
1079 }
1080 else
1081 mpDragBox->EndDocking( maRect, false );
1082 mnStartLines = 0;
1083
1084 mpDragBox = nullptr;
1085}
1086
1087IMPL_LINK( ImplTBDragMgr, SelectHdl, Accelerator&, rAccel, void )void ImplTBDragMgr::LinkStubSelectHdl(void * instance, Accelerator
& data) { return static_cast<ImplTBDragMgr *>(instance
)->SelectHdl(data); } void ImplTBDragMgr::SelectHdl(Accelerator
& rAccel)
1088{
1089 if ( rAccel.GetCurItemId() == KEY_ESCAPE )
1090 EndDragging( false );
1091 else
1092 EndDragging();
1093}
1094
1095void ToolBox::ImplInitToolBoxData()
1096{
1097 // initialize variables
1098 ImplGetWindowImpl()->mbToolBox = true;
1099 mpData.reset(new ImplToolBoxPrivateData);
1100
1101 mpFloatWin = nullptr;
1102 mnDX = 0;
1103 mnDY = 0;
1104 mnMaxItemWidth = 0;
1105 mnMaxItemHeight = 0;
1106 mnWinHeight = 0;
1107 mnLeftBorder = 0;
1108 mnTopBorder = 0;
1109 mnRightBorder = 0;
1110 mnBottomBorder = 0;
1111 mnLastResizeDY = 0;
1112 mnOutStyle = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF
1113 mnHighItemId = 0;
1114 mnCurItemId = 0;
1115 mnDownItemId = 0;
1116 mnCurPos = ITEM_NOTFOUND;
1117 mnLines = 1;
1118 mnCurLine = 1;
1119 mnCurLines = 1;
1120 mnVisLines = 1;
1121 mnFloatLines = 0;
1122 mnDockLines = 0;
1123 mnMouseModifier = 0;
1124 mbDrag = false;
1125 mbUpper = false;
1126 mbLower = false;
1127 mbIn = false;
1128 mbCalc = true;
1129 mbFormat = false;
1130 mbFullPaint = false;
1131 mbHorz = true;
1132 mbScroll = false;
1133 mbLastFloatMode = false;
1134 mbCustomize = false;
1135 mbDragging = false;
1136 mbIsKeyEvent = false;
1137 mbChangingHighlight = false;
1138 mbImagesMirrored = false;
1139 mbLineSpacing = false;
1140 mbIsArranged = false;
1141 meButtonType = ButtonType::SYMBOLONLY;
1142 meAlign = WindowAlign::Top;
1143 meDockAlign = WindowAlign::Top;
1144 meLastStyle = PointerStyle::Arrow;
1145 mnWinStyle = 0;
1146 meLayoutMode = ToolBoxLayoutMode::Normal;
1147 meTextPosition = ToolBoxTextPosition::Right;
1148 mnLastFocusItemId = 0;
1149 mnActivateCount = 0;
1150 mnImagesRotationAngle = 0;
1151
1152 mpStatusListener = new VclStatusListener<ToolBox>(this, ".uno:ImageOrientation");
1153 mpStatusListener->startListening();
1154
1155 mpIdle.reset(new Idle("vcl::ToolBox maIdle update"));
1156 mpIdle->SetPriority( TaskPriority::RESIZE );
1157 mpIdle->SetInvokeHandler( LINK( this, ToolBox, ImplUpdateHdl )::tools::detail::makeLink( ::tools::detail::castTo<ToolBox
*>(this), &ToolBox::LinkStubImplUpdateHdl)
);
1158
1159 // set timeout and handler for dropdown items
1160 mpData->maDropdownTimer.SetTimeout( 250 );
1161 mpData->maDropdownTimer.SetInvokeHandler( LINK( this, ToolBox, ImplDropdownLongClickHdl )::tools::detail::makeLink( ::tools::detail::castTo<ToolBox
*>(this), &ToolBox::LinkStubImplDropdownLongClickHdl)
);
1162 mpData->maDropdownTimer.SetDebugName( "vcl::ToolBox mpData->maDropdownTimer" );
1163}
1164
1165void ToolBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
1166{
1167 // initialize variables
1168 mbScroll = (nStyle & WB_SCROLL) != 0;
1169 mnWinStyle = nStyle;
1170
1171 DockingWindow::ImplInit( pParent, nStyle & ~WB_BORDER );
1172
1173 // dockingwindow's ImplInit removes some bits, so restore them here to allow keyboard handling for toolbars
1174 ImplGetWindowImpl()->mnStyle |= WB_TABSTOP|WB_NODIALOGCONTROL; // always set WB_TABSTOP for ToolBars
1175 ImplGetWindowImpl()->mnStyle &= ~WB_DIALOGCONTROL;
1176
1177 ImplInitSettings(true, true, true);
1178}
1179
1180void ToolBox::ApplyForegroundSettings(vcl::RenderContext& rRenderContext, const StyleSettings& rStyleSettings)
1181{
1182 Color aColor;
1183 if (IsControlForeground())
1184 aColor = GetControlForeground();
1185 else if (Window::GetStyle() & WB_3DLOOK)
1186 aColor = rStyleSettings.GetButtonTextColor();
1187 else
1188 aColor = rStyleSettings.GetWindowTextColor();
1189 rRenderContext.SetTextColor(aColor);
1190 rRenderContext.SetTextFillColor();
1191}
1192
1193void ToolBox::ApplyBackgroundSettings(vcl::RenderContext& rRenderContext, const StyleSettings& rStyleSettings)
1194{
1195 if (IsControlBackground())
1196 {
1197 rRenderContext.SetBackground(GetControlBackground());
1198 SetPaintTransparent(false);
1199 SetParentClipMode();
1200 }
1201 else
1202 {
1203 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ControlPart::Entire)
1204 || (GetAlign() == WindowAlign::Top && !Application::GetSettings().GetStyleSettings().GetPersonaHeader().IsEmpty())
1205 || (GetAlign() == WindowAlign::Bottom && !Application::GetSettings().GetStyleSettings().GetPersonaFooter().IsEmpty()))
1206 {
1207 rRenderContext.SetBackground();
1208 rRenderContext.SetTextColor(rStyleSettings.GetToolTextColor());
1209 SetPaintTransparent(true);
1210 SetParentClipMode(ParentClipMode::NoClip);
1211 mpData->maDisplayBackground = Wallpaper(rStyleSettings.GetFaceColor());
1212 }
1213 else
1214 {
1215 Color aColor;
1216 if (Window::GetStyle() & WB_3DLOOK)
1217 aColor = rStyleSettings.GetFaceColor();
1218 else
1219 aColor = rStyleSettings.GetWindowColor();
1220 rRenderContext.SetBackground(aColor);
1221 SetPaintTransparent(false);
1222 SetParentClipMode();
1223 }
1224 }
1225}
1226
1227void ToolBox::ApplySettings(vcl::RenderContext& rRenderContext)
1228{
1229 mpData->mbNativeButtons = rRenderContext.IsNativeControlSupported(ControlType::Toolbar, ControlPart::Button);
1230
1231 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1232
1233 ApplyControlFont(rRenderContext, rStyleSettings.GetToolFont());
1234 ApplyForegroundSettings(rRenderContext, rStyleSettings);
1235 ApplyBackgroundSettings(rRenderContext, rStyleSettings);
1236}
1237
1238void ToolBox::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
1239{
1240 mpData->mbNativeButtons = IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button );
1241
1242 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1243
1244 if (bFont)
1245 ApplyControlFont(*this, rStyleSettings.GetToolFont());
1246 if (bForeground || bFont)
1247 ApplyForegroundSettings(*this, rStyleSettings);
1248 if (bBackground)
1249 {
1250 ApplyBackgroundSettings(*this, rStyleSettings);
1251 EnableChildTransparentMode(IsPaintTransparent());
1252 }
1253}
1254
1255void ToolBox::doDeferredInit(WinBits nBits)
1256{
1257 VclPtr<vcl::Window> pParent = mpDialogParent;
1258 mpDialogParent = nullptr;
1259 ImplInit(pParent, nBits);
1260 mbIsDeferredInit = false;
1261}
1262
1263void ToolBox::queue_resize(StateChangedType eReason)
1264{
1265 Window::queue_resize(eReason);
1266}
1267
1268ToolBox::ToolBox( vcl::Window* pParent, WinBits nStyle ) :
1269 DockingWindow( WindowType::TOOLBOX )
1270{
1271 ImplInitToolBoxData();
1272 ImplInit( pParent, nStyle );
1273}
1274
1275ToolBox::ToolBox(vcl::Window* pParent, const OString& rID,
1276 const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
1277 : DockingWindow(WindowType::TOOLBOX)
1278{
1279 ImplInitToolBoxData();
1280
1281 loadUI(pParent, rID, rUIXMLDescription, rFrame);
1282
1283 // calculate size of floating windows and switch if the
1284 // toolbox is initially in floating mode
1285 if ( ImplIsFloatingMode() )
1286 mbHorz = true;
1287 else
1288 Resize();
1289
1290 if (!(GetStyle() & WB_HIDE))
1291 Show();
1292}
1293
1294ToolBox::~ToolBox()
1295{
1296 disposeOnce();
1297}
1298
1299void ToolBox::dispose()
1300{
1301 // #103005# make sure our activate/deactivate balance is right
1302 while( mnActivateCount > 0 )
1303 Deactivate();
1304
1305 // terminate popupmode if the floating window is
1306 // still connected
1307 if ( mpFloatWin )
1308 mpFloatWin->EndPopupMode( FloatWinPopupEndFlags::Cancel );
1309 mpFloatWin = nullptr;
1310
1311 // delete private data
1312 mpData.reset();
1313
1314 ImplSVData* pSVData = ImplGetSVData();
1315 delete pSVData->maCtrlData.mpTBDragMgr;
1316 pSVData->maCtrlData.mpTBDragMgr = nullptr;
1317
1318 if (mpStatusListener.is())
1319 mpStatusListener->dispose();
1320
1321 mpFloatWin.clear();
1322
1323 mpIdle.reset();
1324
1325 DockingWindow::dispose();
1326}
1327
1328ImplToolItem* ToolBox::ImplGetItem( sal_uInt16 nItemId ) const
1329{
1330 if (!mpData)
1331 return nullptr;
1332
1333 for (auto & item : mpData->m_aItems)
1334 {
1335 if ( item.mnId == nItemId )
1336 return &item;
1337 }
1338
1339 return nullptr;
1340}
1341
1342static void ImplAddButtonBorder( long &rWidth, long& rHeight, bool bNativeButtons )
1343{
1344 rWidth += SMALLBUTTON_HSIZE7;
1345 rHeight += SMALLBUTTON_VSIZE7;
1346
1347 if( bNativeButtons )
1348 {
1349 // give more border space for rounded buttons
1350 rWidth += 2;
1351 rHeight += 4;
1352 }
1353}
1354
1355bool ToolBox::ImplCalcItem()
1356{
1357 // recalc required ?
1358 if ( !mbCalc )
1359 return false;
1360
1361 ImplDisableFlatButtons();
1362
1363 OutputDevice *pDefault = Application::GetDefaultDevice();
1364 float fScaleFactor = pDefault ? pDefault->GetDPIScaleFactor() : 1.0;
1365
1366 long nDefWidth;
1367 long nDefHeight;
1368 long nMaxWidth = 0;
1369 long nMaxHeight = 0;
1370 long nMinWidth = 6;
1371 long nMinHeight = 6;
1372 long nDropDownArrowWidth = TB_DROPDOWNARROWWIDTH11 * fScaleFactor;
1373#ifdef IOS
1374 nDropDownArrowWidth *= 3;
1375#endif
1376
1377 // set defaults if image or text is needed but empty
1378 nDefWidth = GetDefaultImageSize().Width();
1379 nDefHeight = GetDefaultImageSize().Height();
1380
1381 mnWinHeight = 0;
1382 // determine minimum size necessary in NWF
1383 {
1384 tools::Rectangle aRect( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1385 tools::Rectangle aReg( aRect );
1386 ImplControlValue aVal;
1387 tools::Rectangle aNativeBounds, aNativeContent;
1388 if( IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button ) )
1389 {
1390 if( GetNativeControlRegion( ControlType::Toolbar, ControlPart::Button,
1391 aReg,
1392 ControlState::ENABLED | ControlState::ROLLOVER,
1393 aVal,
1394 aNativeBounds, aNativeContent ) )
1395 {
1396 aRect = aNativeBounds;
1397 if( aRect.GetWidth() > nMinWidth )
1398 nMinWidth = aRect.GetWidth();
1399 if( aRect.GetHeight() > nMinHeight )
1400 nMinHeight = aRect.GetHeight();
1401 if( nDropDownArrowWidth < nMinWidth )
1402 nDropDownArrowWidth = nMinWidth;
1403 if( nMinWidth > mpData->mnMenuButtonWidth )
1404 mpData->mnMenuButtonWidth = nMinWidth;
1405 else if( nMinWidth < TB_MENUBUTTON_SIZE12 )
1406 mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE12;
1407 }
1408 }
1409
1410 // also calculate the area for comboboxes, drop down list boxes and spinfields
1411 // as these are often inserted into toolboxes; set mnWinHeight to the
1412 // greater of those values to prevent toolbar flickering (#i103385#)
1413 aRect = tools::Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1414 aReg = aRect;
1415 if( GetNativeControlRegion( ControlType::Combobox, ControlPart::Entire,
1416 aReg,
1417 ControlState::ENABLED | ControlState::ROLLOVER,
1418 aVal,
1419 aNativeBounds, aNativeContent ) )
1420 {
1421 aRect = aNativeBounds;
1422 if( aRect.GetHeight() > mnWinHeight )
1423 mnWinHeight = aRect.GetHeight();
1424 }
1425 aRect = tools::Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1426 aReg = aRect;
1427 if( GetNativeControlRegion( ControlType::Listbox, ControlPart::Entire,
1428 aReg,
1429 ControlState::ENABLED | ControlState::ROLLOVER,
1430 aVal,
1431 aNativeBounds, aNativeContent ) )
1432 {
1433 aRect = aNativeBounds;
1434 if( aRect.GetHeight() > mnWinHeight )
1435 mnWinHeight = aRect.GetHeight();
1436 }
1437 aRect = tools::Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) );
1438 aReg = aRect;
1439 if( GetNativeControlRegion( ControlType::Spinbox, ControlPart::Entire,
1440 aReg,
1441 ControlState::ENABLED | ControlState::ROLLOVER,
1442 aVal,
1443 aNativeBounds, aNativeContent ) )
1444 {
1445 aRect = aNativeBounds;
1446 if( aRect.GetHeight() > mnWinHeight )
1447 mnWinHeight = aRect.GetHeight();
1448 }
1449 }
1450
1451 if ( ! mpData->m_aItems.empty() )
1452 {
1453 for (auto & item : mpData->m_aItems)
1454 {
1455 item.mbVisibleText = false; // indicates if text will definitely be drawn, influences dropdown pos
1456
1457 if ( item.meType == ToolBoxItemType::BUTTON )
1458 {
1459 bool bImage;
1460 bool bText;
1461
1462 // check if image and/or text exists
1463 bImage = !!item.maImage;
1464 bText = !item.maText.isEmpty();
1465 ButtonType tmpButtonType = determineButtonType( &item, meButtonType ); // default to toolbox setting
1466 if ( bImage || bText )
1467 {
1468
1469 item.mbEmptyBtn = false;
1470
1471 if ( tmpButtonType == ButtonType::SYMBOLONLY )
1472 {
1473 // we're drawing images only
1474 if ( bImage || !bText )
1475 {
1476 item.maItemSize = item.maImage.GetSizePixel();
1477 }
1478 else
1479 {
1480 item.maItemSize = Size( GetCtrlTextWidth( item.maText )+TB_TEXTOFFSET2,
1481 GetTextHeight() );
1482 item.mbVisibleText = true;
1483 }
1484 }
1485 else if ( tmpButtonType == ButtonType::TEXT )
1486 {
1487 // we're drawing text only
1488 if ( bText || !bImage )
1489 {
1490 item.maItemSize = Size( GetCtrlTextWidth( item.maText )+TB_TEXTOFFSET2,
1491 GetTextHeight() );
1492 item.mbVisibleText = true;
1493 }
1494 else
1495 {
1496 item.maItemSize = item.maImage.GetSizePixel();
1497 }
1498 }
1499 else
1500 {
1501 // we're drawing images and text
1502 item.maItemSize.setWidth( bText ? GetCtrlTextWidth( item.maText )+TB_TEXTOFFSET2 : 0 );
1503 item.maItemSize.setHeight( bText ? GetTextHeight() : 0 );
1504
1505 if ( meTextPosition == ToolBoxTextPosition::Right )
1506 {
1507 // leave space between image and text
1508 if( bText )
1509 item.maItemSize.AdjustWidth(TB_IMAGETEXTOFFSET3 );
1510
1511 // image and text side by side
1512 item.maItemSize.AdjustWidth(item.maImage.GetSizePixel().Width() );
1513 if ( item.maImage.GetSizePixel().Height() > item.maItemSize.Height() )
1514 item.maItemSize.setHeight( item.maImage.GetSizePixel().Height() );
1515 }
1516 else
1517 {
1518 // leave space between image and text
1519 if( bText )
1520 item.maItemSize.AdjustHeight(TB_IMAGETEXTOFFSET3 );
1521
1522 // text below image
1523 item.maItemSize.AdjustHeight(item.maImage.GetSizePixel().Height() );
1524 if ( item.maImage.GetSizePixel().Width() > item.maItemSize.Width() )
1525 item.maItemSize.setWidth( item.maImage.GetSizePixel().Width() );
1526 }
1527
1528 item.mbVisibleText = bText;
1529 }
1530 }
1531 else
1532 { // no image and no text
1533 item.maItemSize = Size( nDefWidth, nDefHeight );
1534 item.mbEmptyBtn = true;
1535 }
1536
1537 // save the content size
1538 item.maContentSize = item.maItemSize;
1539
1540 // if required, take window height into consideration
1541 if ( item.mpWindow )
1542 {
1543 long nHeight = item.mpWindow->GetSizePixel().Height();
1544 if ( nHeight > mnWinHeight )
1545 mnWinHeight = nHeight;
1546 }
1547
1548 // add in drop down arrow
1549 if( item.mnBits & ToolBoxItemBits::DROPDOWN )
1550 {
1551 item.maItemSize.AdjustWidth(nDropDownArrowWidth );
1552 item.mnDropDownArrowWidth = nDropDownArrowWidth;
1553 }
1554
1555 // text items will be rotated in vertical mode
1556 // -> swap width and height
1557 if( item.mbVisibleText && !mbHorz )
1558 {
1559 long tmp = item.maItemSize.Width();
1560 item.maItemSize.setWidth( item.maItemSize.Height() );
1561 item.maItemSize.setHeight( tmp );
1562
1563 tmp = item.maContentSize.Width();
1564 item.maContentSize.setWidth( item.maContentSize.Height() );
1565 item.maContentSize.setHeight( tmp );
1566 }
1567 }
1568 else if ( item.meType == ToolBoxItemType::SPACE )
1569 {
1570 item.maItemSize = Size( nDefWidth, nDefHeight );
1571 item.maContentSize = item.maItemSize;
1572 }
1573
1574 if ( item.meType == ToolBoxItemType::BUTTON || item.meType == ToolBoxItemType::SPACE )
1575 {
1576 // add borders
1577 long w = item.maItemSize.Width();
1578 long h = item.maItemSize.Height();
1579 ImplAddButtonBorder( w, h, mpData->mbNativeButtons );
1580 item.maItemSize.setWidth(w);
1581 item.maItemSize.setHeight(h);
1582
1583 if( item.meType == ToolBoxItemType::BUTTON )
1584 {
1585 long nMinW = std::max(nMinWidth, item.maMinimalItemSize.Width());
1586 long nMinH = std::max(nMinHeight, item.maMinimalItemSize.Height());
1587
1588 long nGrowContentWidth = 0;
1589 long nGrowContentHeight = 0;
1590
1591 if( item.maItemSize.Width() < nMinW )
1592 {
1593 nGrowContentWidth = nMinW - item.maItemSize.Width();
1594 item.maItemSize.setWidth( nMinW );
1595 }
1596 if( item.maItemSize.Height() < nMinH )
1597 {
1598 nGrowContentHeight = nMinH - item.maItemSize.Height();
1599 item.maItemSize.setHeight( nMinH );
1600 }
1601
1602 // grow the content size by the additional available space
1603 item.maContentSize.AdjustWidth(nGrowContentWidth );
1604 item.maContentSize.AdjustHeight(nGrowContentHeight );
1605 }
1606
1607 // keep track of max item size
1608 if ( item.maItemSize.Width() > nMaxWidth )
1609 nMaxWidth = item.maItemSize.Width();
1610 if ( item.maItemSize.Height() > nMaxHeight )
1611 nMaxHeight = item.maItemSize.Height();
1612 }
1613 }
1614 }
1615 else
1616 {
1617 nMaxWidth = nDefWidth;
1618 nMaxHeight = nDefHeight;
1619
1620 ImplAddButtonBorder( nMaxWidth, nMaxHeight, mpData->mbNativeButtons );
1621 }
1622
1623 if( !ImplIsFloatingMode() && GetToolboxButtonSize() != ToolBoxButtonSize::DontCare
1624 && ( meTextPosition == ToolBoxTextPosition::Right ) )
1625 {
1626 // make sure all vertical toolbars have the same width and horizontal have the same height
1627 // this depends on the used button sizes
1628 // as this is used for alignment of multiple toolbars
1629 // it is only required for docked toolbars
1630
1631 long nFixedWidth = nDefWidth+nDropDownArrowWidth;
1632 long nFixedHeight = nDefHeight;
1633 ImplAddButtonBorder( nFixedWidth, nFixedHeight, mpData->mbNativeButtons );
1634
1635 if( mbHorz )
1636 nMaxHeight = nFixedHeight;
1637 else
1638 nMaxWidth = nFixedWidth;
1639 }
1640
1641 mbCalc = false;
1642 mbFormat = true;
1643
1644 // do we have to recalc the sizes ?
1645 if ( (nMaxWidth != mnMaxItemWidth) || (nMaxHeight != mnMaxItemHeight) )
1646 {
1647 mnMaxItemWidth = nMaxWidth;
1648 mnMaxItemHeight = nMaxHeight;
1649
1650 return true;
1651 }
1652 else
1653 return false;
1654}
1655
1656ToolBox::ImplToolItems::size_type ToolBox::ImplCalcBreaks( long nWidth, long* pMaxLineWidth, bool bCalcHorz ) const
1657{
1658 sal_uLong nLineStart = 0;
1659 sal_uLong nGroupStart = 0;
1660 long nLineWidth = 0;
1661 long nCurWidth;
1662 long nLastGroupLineWidth = 0;
1663 long nMaxLineWidth = 0;
1664 ImplToolItems::size_type nLines = 1;
1665 bool bWindow;
1666 bool bBreak = false;
1667 long nWidthTotal = nWidth;
1668 long nMenuWidth = 0;
1669
1670 // when docked the menubutton will be in the first line
1671 if( IsMenuEnabled() && !ImplIsFloatingMode() )
1672 nMenuWidth = mpData->maMenubuttonItem.maItemSize.Width();
1673
1674 // we need to know which item is the last visible one to be able to add
1675 // the menu width in case we are unable to show all the items
1676 ImplToolItems::iterator it, lastVisible;
1677 for ( it = mpData->m_aItems.begin(); it != mpData->m_aItems.end(); ++it )
1678 {
1679 if ( it->mbVisible )
1680 lastVisible = it;
1681 }
1682
1683 it = mpData->m_aItems.begin();
1684 while ( it != mpData->m_aItems.end() )
1685 {
1686 it->mbBreak = bBreak;
1687 bBreak = false;
1688
1689 if ( it->mbVisible )
1690 {
1691 bWindow = false;
1692 bBreak = false;
1693 nCurWidth = 0;
1694
1695 if ( it->meType == ToolBoxItemType::BUTTON || it->meType == ToolBoxItemType::SPACE )
1696 {
1697 if ( bCalcHorz )
1698 nCurWidth = it->maItemSize.Width();
1699 else
1700 nCurWidth = it->maItemSize.Height();
1701
1702 if ( it->mpWindow && bCalcHorz )
1703 {
1704 long nWinItemWidth = it->mpWindow->GetSizePixel().Width();
1705 if ( !mbScroll || (nWinItemWidth <= nWidthTotal) )
1706 {
1707 nCurWidth = nWinItemWidth;
1708 bWindow = true;
1709 }
1710 else
1711 {
1712 if ( it->mbEmptyBtn )
1713 {
1714 nCurWidth = 0;
1715 }
1716 }
1717 }
1718
1719 // in case we are able to show all the items, we do not want
1720 // to show the toolbar's menu; otherwise yes
1721 if ( ( ( it == lastVisible ) && (nLineWidth+nCurWidth > nWidthTotal) && mbScroll ) ||
1722 ( ( it != lastVisible ) && (nLineWidth+nCurWidth+nMenuWidth > nWidthTotal) && mbScroll ) )
1723 bBreak = true;
1724 }
1725 else if ( it->meType == ToolBoxItemType::SEPARATOR )
1726 {
1727 nCurWidth = it->mnSepSize;
1728 if ( !ImplIsFloatingMode() && ( it != lastVisible ) && (nLineWidth+nCurWidth+nMenuWidth > nWidthTotal) )
1729 bBreak = true;
1730 }
1731 // treat breaks as separators, except when using old style toolbars (ie. no menu button)
1732 else if ( (it->meType == ToolBoxItemType::BREAK) && !IsMenuEnabled() )
1733 bBreak = true;
1734
1735 if ( bBreak )
1736 {
1737 nLines++;
1738
1739 // Add break before the entire group or take group apart?
1740 if ( (it->meType == ToolBoxItemType::BREAK) ||
1741 (nLineStart == nGroupStart) )
1742 {
1743 if ( nLineWidth > nMaxLineWidth )
1744 nMaxLineWidth = nLineWidth;
1745
1746 nLineWidth = 0;
1747 nLineStart = it - mpData->m_aItems.begin();
1748 nGroupStart = nLineStart;
1749 it->mbBreak = true;
1750 bBreak = false;
1751 }
1752 else
1753 {
1754 if ( nLastGroupLineWidth > nMaxLineWidth )
1755 nMaxLineWidth = nLastGroupLineWidth;
1756
1757 // if the break is added before the group, set it to
1758 // beginning of line and re-calculate
1759 nLineWidth = 0;
1760 nLineStart = nGroupStart;
1761 it = mpData->m_aItems.begin() + nGroupStart;
1762 continue;
1763 }
1764 }
1765 else
1766 {
1767 if( ImplIsFloatingMode() || !IsMenuEnabled() ) // no group breaking when being docked single-line
1768 {
1769 if ( (it->meType != ToolBoxItemType::BUTTON) || bWindow )
1770 {
1771 // found separator or break
1772 nLastGroupLineWidth = nLineWidth;
1773 nGroupStart = it - mpData->m_aItems.begin();
1774 if ( !bWindow )
1775 nGroupStart++;
1776 }
1777 }
1778 }
1779
1780 nLineWidth += nCurWidth;
1781 }
1782
1783 ++it;
1784 }
1785
1786 if ( pMaxLineWidth )
1787 {
1788 if ( nLineWidth > nMaxLineWidth )
1789 nMaxLineWidth = nLineWidth;
1790
1791 if( ImplIsFloatingMode() && !ImplIsInPopupMode() )
1792 {
1793 // leave enough space to display buttons in the decoration
1794 long aMinWidth = 2 * GetSettings().GetStyleSettings().GetFloatTitleHeight();
1795 if( nMaxLineWidth < aMinWidth )
1796 nMaxLineWidth = aMinWidth;
1797 }
1798 *pMaxLineWidth = nMaxLineWidth;
1799 }
1800
1801 return nLines;
1802}
1803
1804Size ToolBox::ImplGetOptimalFloatingSize()
1805{
1806 if( !ImplIsFloatingMode() )
1807 return Size();
1808
1809 Size aCurrentSize( mnDX, mnDY );
1810 Size aSize1( aCurrentSize );
1811 Size aSize2( aCurrentSize );
1812
1813 // try to preserve current height
1814
1815 // calc number of floating lines for current window height
1816 ImplToolItems::size_type nFloatLinesHeight = ImplCalcLines( mnDY );
1817 // calc window size according to this number
1818 aSize1 = ImplCalcFloatSize( nFloatLinesHeight );
1819
1820 if( aCurrentSize == aSize1 )
1821 return aSize1;
1822
1823 // try to preserve current width
1824
1825 long nLineHeight = std::max( mnWinHeight, mnMaxItemHeight );
1826 int nBorderX = 2*TB_BORDER_OFFSET14 + mnLeftBorder + mnRightBorder;
1827 int nBorderY = 2*TB_BORDER_OFFSET22 + mnTopBorder + mnBottomBorder;
1828 Size aSz( aCurrentSize );
1829 long maxX;
1830 ImplToolItems::size_type nLines = ImplCalcBreaks( aSz.Width()-nBorderX, &maxX, mbHorz );
1831
1832 ImplToolItems::size_type manyLines = 1000;
1833 Size aMinimalFloatSize = ImplCalcFloatSize( manyLines );
1834
1835 aSz.setHeight( nBorderY + nLineHeight * nLines );
1836 // line space when more than one line
1837 if ( mbLineSpacing )
1838 aSz.AdjustHeight((nLines-1)*TB_LINESPACING3 );
1839
1840 aSz.setWidth( nBorderX + maxX );
1841
1842 // avoid clipping of any items
1843 if( aSz.Width() < aMinimalFloatSize.Width() )
1844 aSize2 = ImplCalcFloatSize( nLines );
1845 else
1846 aSize2 = aSz;
1847
1848 if( aCurrentSize == aSize2 )
1849 return aSize2;
1850
1851 // set the size with the smallest delta as the current size
1852 long dx1 = std::abs( mnDX - aSize1.Width() );
1853 long dy1 = std::abs( mnDY - aSize1.Height() );
1854
1855 long dx2 = std::abs( mnDX - aSize2.Width() );
1856 long dy2 = std::abs( mnDY - aSize2.Height() );
1857
1858 if( dx1*dy1 < dx2*dy2 )
1859 aCurrentSize = aSize1;
1860 else
1861 aCurrentSize = aSize2;
1862
1863 return aCurrentSize;
1864}
1865
1866namespace
1867{
1868void lcl_hideDoubleSeparators( ToolBox::ImplToolItems& rItems )
1869{
1870 bool bLastSep( true );
1871 ToolBox::ImplToolItems::iterator it;
1872 for ( it = rItems.begin(); it != rItems.end(); ++it )
1873 {
1874 if ( it->meType == ToolBoxItemType::SEPARATOR )
1875 {
1876 it->mbVisible = false;
1877 if ( !bLastSep )
1878 {
1879 // check if any visible items have to appear behind it
1880 if (std::any_of(it + 1, rItems.end(), [](const ImplToolItem& rItem) {
1881 return (rItem.meType == ToolBoxItemType::BUTTON) && rItem.mbVisible; }))
1882 it->mbVisible = true;
1883 }
1884 bLastSep = true;
1885 }
1886 else if ( it->mbVisible )
1887 bLastSep = false;
1888 }
1889}
1890}
1891
1892void ToolBox::ImplFormat( bool bResize )
1893{
1894 // Has to re-formatted
1895 if ( !mbFormat )
1896 return;
1897
1898 mpData->ImplClearLayoutData();
1899
1900 // recalculate positions and sizes
1901 tools::Rectangle aEmptyRect;
1902 long nLineSize;
1903 long nLeft;
1904 long nTop;
1905 long nMax; // width of layoutarea in pixels
1906 ImplToolItems::size_type nFormatLine;
1907 bool bMustFullPaint;
1908
1909 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
1910 bool bIsInPopupMode = ImplIsInPopupMode();
1911
1912 maFloatSizes.clear();
1913
1914 // compute border sizes
1915 ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder, mnRightBorder, mnBottomBorder );
1916
1917 // update drag area (where the 'grip' will be placed)
1918 tools::Rectangle aOldDragRect;
1919 if( pWrapper )
1920 aOldDragRect = pWrapper->GetDragArea();
1921 ImplUpdateDragArea();
1922
1923 bMustFullPaint = ImplCalcItem();
1924
1925 // calculate new size during interactive resize or
1926 // set computed size when formatting only
1927 if ( ImplIsFloatingMode() )
1928 {
1929 if ( bResize )
1930 mnFloatLines = ImplCalcLines( mnDY );
1931 else
1932 SetOutputSizePixel( ImplGetOptimalFloatingSize() );
1933 }
1934
1935 // Horizontal
1936 if ( mbHorz )
1937 {
1938 long nBottom;
1939 // nLineSize: height of a single line, will fit highest item
1940 nLineSize = mnMaxItemHeight;
1941
1942 if ( mnWinHeight > mnMaxItemHeight )
1943 nLineSize = mnWinHeight;
1944
1945 if ( mbScroll )
1946 {
1947 nMax = mnDX;
1948 mnVisLines = ImplCalcLines( mnDY );
1949 }
1950 else
1951 {
1952 // layout over all lines
1953 mnVisLines = mnLines;
1954 nMax = TB_MAXNOSCROLL32765;
1955 }
1956
1957 // add in all border offsets
1958 if ( mnWinStyle & WB_BORDER )
1959 {
1960 nLeft = TB_BORDER_OFFSET14 + mnLeftBorder;
1961 nTop = TB_BORDER_OFFSET22 + mnTopBorder;
1962 nBottom = TB_BORDER_OFFSET14 + mnBottomBorder;
1963 nMax -= nLeft + TB_BORDER_OFFSET14 + mnRightBorder;
1964 }
1965 else
1966 {
1967 nLeft = 0;
1968 nTop = 0;
1969 nBottom = 0;
1970 }
1971
1972 // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
1973 // we have to center all items in the window height
1974 if( IsMenuEnabled() && !ImplIsFloatingMode() )
1975 {
1976 long nWinHeight = mnDY - nTop - nBottom;
1977 if( nWinHeight > nLineSize )
1978 nLineSize = nWinHeight;
1979 }
1980 }
1981 else
1982 {
1983 long nRight;
1984 nLineSize = mnMaxItemWidth;
1985
1986 if ( mbScroll )
1987 {
1988 mnVisLines = ImplCalcLines( mnDX );
1989 nMax = mnDY;
1990 }
1991 else
1992 {
1993 mnVisLines = mnLines;
1994 nMax = TB_MAXNOSCROLL32765;
1995 }
1996
1997 if ( mnWinStyle & WB_BORDER )
1998 {
1999 nTop = TB_BORDER_OFFSET14 + mnTopBorder;
2000 nLeft = TB_BORDER_OFFSET22 + mnLeftBorder;
2001 nRight = TB_BORDER_OFFSET22 + mnRightBorder;
2002 nMax -= nTop + TB_BORDER_OFFSET14 + mnBottomBorder;
2003 }
2004 else
2005 {
2006 nLeft = 0;
2007 nTop = 0;
2008 nRight = 0;
2009 }
2010
2011 // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu)
2012 // we have to center all items in the window height
2013 if( !ImplIsFloatingMode() && IsMenuEnabled() )
2014 {
2015 long nWinWidth = mnDX - nLeft - nRight;
2016 if( nWinWidth > nLineSize )
2017 nLineSize = nWinWidth;
2018 }
2019 }
2020
2021 // no calculation if the window has no size (nMax=0)
2022 // non scrolling toolboxes must be computed though
2023 if ( (nMax <= 0) && mbScroll )
2024 {
2025 mnVisLines = 1;
2026 mnCurLine = 1;
2027 mnCurLines = 1;
2028
2029 for (auto & item : mpData->m_aItems)
2030 {
2031 item.maRect = aEmptyRect;
2032 }
2033
2034 maLowerRect = aEmptyRect;
2035 maUpperRect = aEmptyRect;
2036 }
2037 else
2038 {
2039 // init start values
2040 long nX = nLeft; // top-left offset
2041 long nY = nTop;
2042 nFormatLine = 1;
2043
2044 // save old scroll rectangles and reset them
2045 tools::Rectangle aOldLowerRect = maLowerRect;
2046 tools::Rectangle aOldUpperRect = maUpperRect;
2047 tools::Rectangle aOldMenubuttonRect = mpData->maMenubuttonItem.maRect;
2048 maUpperRect = aEmptyRect;
2049 maLowerRect = aEmptyRect;
2050 mpData->maMenubuttonItem.maRect = aEmptyRect;
2051
2052 // do we have any toolbox items at all ?
2053 if ( !mpData->m_aItems.empty() || IsMenuEnabled() )
2054 {
2055 lcl_hideDoubleSeparators( mpData->m_aItems );
2056
2057 // compute line breaks and visible lines give the current window width (nMax)
2058 // the break indicators will be stored within each item (it->mbBreak)
2059 mnCurLines = ImplCalcBreaks( nMax, nullptr, mbHorz );
2060
2061 // check for scrollbar buttons or dropdown menu
2062 // (if a menu is enabled, this will be used to store clipped
2063 // items and no scroll buttons will appear)
2064 if ( (!ImplIsFloatingMode() && (mnCurLines > mnVisLines) && mbScroll ) ||
2065 IsMenuEnabled() )
2066 {
2067 // compute linebreaks again, incorporating scrollbar buttons
2068 if( !IsMenuEnabled() )
2069 {
2070 nMax -= TB_SPIN_SIZE14+TB_SPIN_OFFSET2;
2071 mnCurLines = ImplCalcBreaks( nMax, nullptr, mbHorz );
2072 }
2073
2074 // compute scroll rectangles or menu button
2075 if ( mbHorz )
2076 {
2077 if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2078 {
2079 if( !ImplIsFloatingMode() )
2080 {
2081 mpData->maMenubuttonItem.maRect.SetRight( mnDX - 2 );
2082 mpData->maMenubuttonItem.maRect.SetTop( nTop );
2083 mpData->maMenubuttonItem.maRect.SetBottom( mnDY-mnBottomBorder-TB_BORDER_OFFSET22-1 );
2084 }
2085 else
2086 {
2087 mpData->maMenubuttonItem.maRect.SetRight( mnDX - mnRightBorder-TB_BORDER_OFFSET14-1 );
2088 mpData->maMenubuttonItem.maRect.SetTop( nTop );
2089 mpData->maMenubuttonItem.maRect.SetBottom( mnDY-mnBottomBorder-TB_BORDER_OFFSET22-1 );
2090 }
2091 mpData->maMenubuttonItem.maRect.SetLeft( mpData->maMenubuttonItem.maRect.Right() - mpData->mnMenuButtonWidth );
2092 }
2093 else
2094 {
2095 maUpperRect.SetLeft( nLeft+nMax+TB_SPIN_OFFSET2 );
2096 maUpperRect.SetRight( maUpperRect.Left()+TB_SPIN_SIZE14-1 );
2097 maUpperRect.SetTop( nTop );
2098 maLowerRect.SetBottom( mnDY-mnBottomBorder-TB_BORDER_OFFSET22-1 );
2099 maLowerRect.SetLeft( maUpperRect.Left() );
2100 maLowerRect.SetRight( maUpperRect.Right() );
2101 maUpperRect.SetBottom( maUpperRect.Top() +
2102 (maLowerRect.Bottom()-maUpperRect.Top())/2 );
2103 maLowerRect.SetTop( maUpperRect.Bottom() );
2104 }
2105 }
2106 else
2107 {
2108 if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2109 {
2110 if( !ImplIsFloatingMode() )
2111 {
2112 mpData->maMenubuttonItem.maRect.SetBottom( mnDY - 2 );
2113 mpData->maMenubuttonItem.maRect.SetLeft( nLeft );
2114 mpData->maMenubuttonItem.maRect.SetRight( mnDX-mnRightBorder-TB_BORDER_OFFSET22-1 );
2115 }
2116 else
2117 {
2118 mpData->maMenubuttonItem.maRect.SetBottom( mnDY - mnBottomBorder-TB_BORDER_OFFSET14-1 );
2119 mpData->maMenubuttonItem.maRect.SetLeft( nLeft );
2120 mpData->maMenubuttonItem.maRect.SetRight( mnDX-mnRightBorder-TB_BORDER_OFFSET22-1 );
2121 }
2122 mpData->maMenubuttonItem.maRect.SetTop( mpData->maMenubuttonItem.maRect.Bottom() - mpData->mnMenuButtonWidth );
2123 }
2124 else
2125 {
2126 maUpperRect.SetTop( nTop+nMax+TB_SPIN_OFFSET2 );
2127 maUpperRect.SetBottom( maUpperRect.Top()+TB_SPIN_SIZE14-1 );
2128 maUpperRect.SetLeft( nLeft );
2129 maLowerRect.SetRight( mnDX-mnRightBorder-TB_BORDER_OFFSET22-1 );
2130 maLowerRect.SetTop( maUpperRect.Top() );
2131 maLowerRect.SetBottom( maUpperRect.Bottom() );
2132 maUpperRect.SetRight( maUpperRect.Left() +
2133 (maLowerRect.Right()-maUpperRect.Left())/2 );
2134 maLowerRect.SetLeft( maUpperRect.Right() );
2135 }
2136 }
2137 }
2138
2139 // no scrolling when there is a "more"-menu
2140 // anything will "fit" in a single line then
2141 if( IsMenuEnabled() )
2142 mnCurLines = 1;
2143
2144 // determine the currently visible line
2145 if ( mnVisLines >= mnCurLines )
2146 mnCurLine = 1;
2147 else if ( mnCurLine+mnVisLines-1 > mnCurLines )
2148 mnCurLine = mnCurLines - (mnVisLines-1);
2149
2150 long firstItemCenter = 0;
2151 for (auto & item : mpData->m_aItems)
2152 {
2153 item.mbShowWindow = false;
2154
2155 // check for line break and advance nX/nY accordingly
2156 if ( item.mbBreak )
2157 {
2158 nFormatLine++;
2159
2160 // increment starting with the second line
2161 if ( nFormatLine > mnCurLine )
2162 {
2163 if ( mbHorz )
2164 {
2165 nX = nLeft;
2166 if ( mbLineSpacing )
2167 nY += nLineSize+TB_LINESPACING3;
2168 else
2169 nY += nLineSize;
2170 }
2171 else
2172 {
2173 nY = nTop;
2174 if ( mbLineSpacing )
2175 nX += nLineSize+TB_LINESPACING3;
2176 else
2177 nX += nLineSize;
2178 }
2179 }
2180 }
2181
2182 if ( !item.mbVisible || (nFormatLine < mnCurLine) ||
2183 (nFormatLine > mnCurLine+mnVisLines-1) )
2184 // item is not visible
2185 item.maCalcRect = aEmptyRect;
2186 else
2187 {
2188 // 1. determine current item width/height
2189 // take window size and orientation into account, because this affects the size of item windows
2190
2191 Size aCurrentItemSize( item.GetSize( mbHorz, mbScroll, nMax, Size(mnMaxItemWidth, mnMaxItemHeight) ) );
2192
2193 // 2. position item rect and use size from step 1
2194 // items will be centered horizontally (if mbHorz) or vertically
2195 // advance nX and nY accordingly
2196
2197 if ( mbHorz )
2198 {
2199 // In special mode Locked horizontal positions of all items remain unchanged.
2200
2201 if ( mbIsArranged && meLayoutMode == ToolBoxLayoutMode::Locked && mnLines == 1 && item.maRect.Left() > 0 )
2202 nX = item.maRect.Left();
2203 item.maCalcRect.SetLeft( nX );
2204
2205 // In special mode Locked first item's vertical position remains unchanged. Consecutive items vertical
2206 // positions are centered around first item's vertical position. If an item's height exceeds available
2207 // space, item's vertical position remains unchanged too.
2208
2209 if ( mbIsArranged && meLayoutMode == ToolBoxLayoutMode::Locked && mnLines == 1 )
2210 if ( firstItemCenter > 0 )
2211 if ( firstItemCenter-aCurrentItemSize.Height()/2 > nY )
2212 item.maCalcRect.SetTop( firstItemCenter-aCurrentItemSize.Height()/2 );
2213 else
2214 item.maCalcRect.SetTop( item.maRect.Top() );
2215 else
2216 {
2217 item.maCalcRect.SetTop( item.maRect.Top() );
2218 firstItemCenter = item.maRect.Top()+aCurrentItemSize.Height()/2;
2219 }
2220 else
2221 item.maCalcRect.SetTop( nY+(nLineSize-aCurrentItemSize.Height())/2 );
2222 item.maCalcRect.SetRight( nX+aCurrentItemSize.Width()-1 );
2223 item.maCalcRect.SetBottom( item.maCalcRect.Top()+aCurrentItemSize.Height()-1 );
2224 nX += aCurrentItemSize.Width();
2225 }
2226 else
2227 {
2228 item.maCalcRect.SetLeft( nX+(nLineSize-aCurrentItemSize.Width())/2 );
2229 item.maCalcRect.SetTop( nY );
2230 item.maCalcRect.SetRight( item.maCalcRect.Left()+aCurrentItemSize.Width()-1 );
2231 item.maCalcRect.SetBottom( nY+aCurrentItemSize.Height()-1 );
2232 nY += aCurrentItemSize.Height();
2233 }
2234 }
2235
2236 // position window items into calculated item rect
2237 if ( item.mpWindow )
2238 {
2239 if ( item.mbShowWindow )
2240 {
2241 Point aPos( item.maCalcRect.Left(), item.maCalcRect.Top() );
2242
2243 assert( item.maCalcRect.Top() >= 0 )(static_cast <bool> (item.maCalcRect.Top() >= 0) ? void
(0) : __assert_fail ("item.maCalcRect.Top() >= 0", "/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
, 2243, __extension__ __PRETTY_FUNCTION__))
;
2244
2245 item.mpWindow->SetPosPixel( aPos );
2246 item.mpWindow->Show();
2247 }
2248 else
2249 item.mpWindow->Hide();
2250 }
2251 } // end of loop over all items
2252 mbIsArranged = true;
2253 }
2254 else
2255 // we have no toolbox items
2256 mnCurLines = 1;
2257
2258 if( IsMenuEnabled() && ImplIsFloatingMode() && !ImplHasExternalMenubutton() && !bIsInPopupMode )
2259 {
2260 // custom menu will be the last button in floating mode
2261 ImplToolItem &rIt = mpData->maMenubuttonItem;
2262
2263 if ( mbHorz )
2264 {
2265 rIt.maRect.SetLeft( nX+TB_MENUBUTTON_OFFSET2 );
2266 rIt.maRect.SetTop( nY );
2267 rIt.maRect.SetRight( rIt.maRect.Left() + mpData->mnMenuButtonWidth );
2268 rIt.maRect.SetBottom( nY+nLineSize-1 );
2269 nX += rIt.maItemSize.Width();
Value stored to 'nX' is never read
2270 }
2271 else
2272 {
2273 rIt.maRect.SetLeft( nX );
2274 rIt.maRect.SetTop( nY+TB_MENUBUTTON_OFFSET2 );
2275 rIt.maRect.SetRight( nX+nLineSize-1 );
2276 rIt.maRect.SetBottom( rIt.maRect.Top() + mpData->mnMenuButtonWidth );
2277 nY += rIt.maItemSize.Height();
2278 }
2279 }
2280
2281 // if toolbox visible trigger paint for changed regions
2282 if ( IsVisible() && !mbFullPaint )
2283 {
2284 if ( bMustFullPaint )
2285 {
2286 maPaintRect = tools::Rectangle( mnLeftBorder, mnTopBorder,
2287 mnDX-mnRightBorder, mnDY-mnBottomBorder );
2288 }
2289 else
2290 {
2291 if ( aOldLowerRect != maLowerRect )
2292 {
2293 maPaintRect.Union( maLowerRect );
2294 maPaintRect.Union( aOldLowerRect );
2295 }
2296 if ( aOldUpperRect != maUpperRect )
2297 {
2298 maPaintRect.Union( maUpperRect );
2299 maPaintRect.Union( aOldUpperRect );
2300 }
2301 if ( aOldMenubuttonRect != mpData->maMenubuttonItem.maRect )
2302 {
2303 maPaintRect.Union( mpData->maMenubuttonItem.maRect );
2304 maPaintRect.Union( aOldMenubuttonRect );
2305 }
2306 if ( pWrapper && aOldDragRect != pWrapper->GetDragArea() )
2307 {
2308 maPaintRect.Union( pWrapper->GetDragArea() );
2309 maPaintRect.Union( aOldDragRect );
2310 }
2311
2312 for (auto const& item : mpData->m_aItems)
2313 {
2314 if ( item.maRect != item.maCalcRect )
2315 {
2316 maPaintRect.Union( item.maRect );
2317 maPaintRect.Union( item.maCalcRect );
2318 }
2319 }
2320 }
2321
2322 Invalidate( maPaintRect );
2323 }
2324
2325 // store the new calculated item rects
2326 maPaintRect = aEmptyRect;
2327 for (auto & item : mpData->m_aItems)
2328 item.maRect = item.maCalcRect;
2329 }
2330
2331 // indicate formatting is done
2332 mbFormat = false;
2333}
2334
2335IMPL_LINK_NOARG(ToolBox, ImplDropdownLongClickHdl, Timer *, void)void ToolBox::LinkStubImplDropdownLongClickHdl(void * instance
, Timer * data) { return static_cast<ToolBox *>(instance
)->ImplDropdownLongClickHdl(data); } void ToolBox::ImplDropdownLongClickHdl
(__attribute__ ((unused)) Timer *)
2336{
2337 if (mnCurPos == ITEM_NOTFOUND ||
2338 !(mpData->m_aItems[ mnCurPos ].mnBits & ToolBoxItemBits::DROPDOWN))
2339 return;
2340
2341 mpData->mbDropDownByKeyboard = false;
2342 mpData->maDropdownClickHdl.Call( this );
2343
2344 // do not reset data if the dropdown handler opened a floating window
2345 // see ImplFloatControl()
2346 if( !mpFloatWin )
2347 {
2348 // no floater was opened
2349 Deactivate();
2350 InvalidateItem(mnCurPos);
2351
2352 mnCurPos = ITEM_NOTFOUND;
2353 mnCurItemId = 0;
2354 mnDownItemId = 0;
2355 mnMouseModifier = 0;
2356 mnHighItemId = 0;
2357 }
2358}
2359
2360IMPL_LINK_NOARG(ToolBox, ImplUpdateHdl, Timer *, void)void ToolBox::LinkStubImplUpdateHdl(void * instance, Timer * data
) { return static_cast<ToolBox *>(instance)->ImplUpdateHdl
(data); } void ToolBox::ImplUpdateHdl(__attribute__ ((unused)
) Timer *)
2361{
2362
2363 if( mbFormat && mpData )
2364 ImplFormat();
2365}
2366
2367static void ImplDrawMoreIndicator(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
2368{
2369 const Image pImage(StockImage::Yes, CHEVRON"sfx2/res/chevron.png");
2370 Size aImageSize = pImage.GetSizePixel();
2371 long x = rRect.Left() + (rRect.getWidth() - aImageSize.Width())/2;
2372 long y = rRect.Top() + (rRect.getHeight() - aImageSize.Height())/2;
2373 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
2374
2375 rRenderContext.DrawImage(Point(x,y), pImage, nImageStyle);
2376}
2377
2378static void ImplDrawDropdownArrow(vcl::RenderContext& rRenderContext, const tools::Rectangle& rDropDownRect, bool bSetColor, bool bRotate )
2379{
2380 bool bLineColor = rRenderContext.IsLineColor();
2381 bool bFillColor = rRenderContext.IsFillColor();
2382 Color aOldFillColor = rRenderContext.GetFillColor();
2383 Color aOldLineColor = rRenderContext.GetLineColor();
2384 rRenderContext.SetLineColor();
2385
2386 if ( bSetColor )
2387 {
2388 if (rRenderContext.GetSettings().GetStyleSettings().GetFaceColor().IsDark())
2389 rRenderContext.SetFillColor(COL_WHITE);
2390 else
2391 rRenderContext.SetFillColor(COL_BLACK);
2392 }
2393
2394 tools::Polygon aPoly(4);
2395
2396 // the assumption is, that the width always specifies the size of the expected arrow.
2397 const long nMargin = round(2 * rRenderContext.GetDPIScaleFactor());
2398 const long nSize = rDropDownRect.getWidth() - 2 * nMargin;
2399 const long nHalfSize = (nSize + 1) / 2;
2400 const long x = rDropDownRect.Left() + nMargin + (bRotate ? (rDropDownRect.getWidth() - nHalfSize) / 2 : 0);
2401 const long y = rDropDownRect.Top() + nMargin + (rDropDownRect.getHeight() - (bRotate ? nSize : nHalfSize)) / 2;
2402
2403 aPoly.SetPoint(Point(x, y), 0);
2404 if (bRotate) // >
2405 {
2406 aPoly.SetPoint(Point(x, y + nSize), 1);
2407 aPoly.SetPoint(Point(x + nHalfSize, y + nHalfSize), 2);
2408 }
2409 else // v
2410 {
2411 aPoly.SetPoint(Point(x + nHalfSize, y + nHalfSize), 1);
2412 aPoly.SetPoint(Point(x + nSize, y), 2);
2413 }
2414 aPoly.SetPoint(Point(x, y), 3);
2415
2416 auto aaflags = rRenderContext.GetAntialiasing();
2417 rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
2418 rRenderContext.DrawPolygon( aPoly );
2419 rRenderContext.SetAntialiasing(aaflags);
2420
2421 if( bFillColor )
2422 rRenderContext.SetFillColor(aOldFillColor);
2423 else
2424 rRenderContext.SetFillColor();
2425 if( bLineColor )
2426 rRenderContext.SetLineColor(aOldLineColor);
2427 else
2428 rRenderContext.SetLineColor();
2429}
2430
2431void ToolBox::ImplDrawMenuButton(vcl::RenderContext& rRenderContext, bool bHighlight)
2432{
2433 if (mpData->maMenubuttonItem.maRect.IsEmpty())
2434 return;
2435
2436 // #i53937# paint menu button only if necessary
2437 if (!ImplHasClippedItems())
2438 return;
2439
2440 // execute pending paint requests
2441 ImplCheckUpdate();
2442
2443 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
2444
2445 // draw the 'more' indicator / button (>>)
2446 ImplErase(rRenderContext, mpData->maMenubuttonItem.maRect, bHighlight);
2447
2448 if (bHighlight)
2449 ImplDrawButton(rRenderContext, mpData->maMenubuttonItem.maRect, 2, false, true, false );
2450
2451 if (ImplHasClippedItems())
2452 ImplDrawMoreIndicator(rRenderContext, mpData->maMenubuttonItem.maRect);
2453
2454 // store highlight state
2455 mpData->mbMenubuttonSelected = bHighlight;
2456
2457 // restore colors
2458 rRenderContext.Pop();
2459}
2460
2461void ToolBox::ImplDrawSpin(vcl::RenderContext& rRenderContext)
2462{
2463 bool bTmpUpper;
2464 bool bTmpLower;
2465
2466 if ( maUpperRect.IsEmpty() || maLowerRect.IsEmpty() )
2467 return;
2468
2469 bTmpUpper = mnCurLine > 1;
2470
2471 bTmpLower = mnCurLine+mnVisLines-1 < mnCurLines;
2472
2473 if ( !IsEnabled() )
2474 {
2475 bTmpUpper = false;
2476 bTmpLower = false;
2477 }
2478
2479 ImplDrawUpDownButtons(rRenderContext, maUpperRect, maLowerRect,
2480 false/*bUpperIn*/, false/*bLowerIn*/, bTmpUpper, bTmpLower, !mbHorz);
2481}
2482
2483void ToolBox::ImplDrawSeparator(vcl::RenderContext& rRenderContext, ImplToolItems::size_type nPos, const tools::Rectangle& rRect)
2484{
2485 if ( nPos >= mpData->m_aItems.size() - 1 )
2486 // no separator if it's the last item
2487 return;
2488
2489 ImplToolItem* pItem = &mpData->m_aItems[nPos];
2490 ImplToolItem* pPreviousItem = &mpData->m_aItems[nPos-1];
2491 ImplToolItem* pNextItem = &mpData->m_aItems[nPos+1];
2492
2493 if ( ( pPreviousItem->mbShowWindow && pNextItem->mbShowWindow ) || pNextItem->mbBreak )
2494 // no separator between two windows or before a break
2495 return;
2496
2497 bool bNativeOk = false;
2498 ControlPart nPart = IsHorizontal() ? ControlPart::SeparatorVert : ControlPart::SeparatorHorz;
2499 if (rRenderContext.IsNativeControlSupported(ControlType::Toolbar, nPart))
2500 {
2501 ImplControlValue aControlValue;
2502 bNativeOk = rRenderContext.DrawNativeControl(ControlType::Toolbar, nPart, rRect, ControlState::NONE, aControlValue, OUString());
2503 }
2504
2505 /* Draw the widget only if it can't be drawn natively. */
2506 if (bNativeOk)
2507 return;
2508
2509 long nCenterPos, nSlim;
2510 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2511 rRenderContext.SetLineColor(rStyleSettings.GetSeparatorColor());
2512 if (IsHorizontal())
2513 {
2514 nSlim = (pItem->maRect.Bottom() - pItem->maRect.Top ()) / 4;
2515 nCenterPos = pItem->maRect.Center().X();
2516 rRenderContext.DrawLine(Point(nCenterPos, pItem->maRect.Top() + nSlim),
2517 Point(nCenterPos, pItem->maRect.Bottom() - nSlim));
2518 }
2519 else
2520 {
2521 nSlim = (pItem->maRect.Right() - pItem->maRect.Left ()) / 4;
2522 nCenterPos = pItem->maRect.Center().Y();
2523 rRenderContext.DrawLine(Point(pItem->maRect.Left() + nSlim, nCenterPos),
2524 Point(pItem->maRect.Right() - nSlim, nCenterPos));
2525 }
2526}
2527
2528void ToolBox::ImplDrawButton(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect, sal_uInt16 highlight,
2529 bool bChecked, bool bEnabled, bool bIsWindow )
2530{
2531 // draws toolbar button background either native or using a coloured selection
2532 // if bIsWindow is true, the corresponding item is a control and only a selection border will be drawn
2533
2534 bool bNativeOk = false;
2535 if( !bIsWindow && rRenderContext.IsNativeControlSupported( ControlType::Toolbar, ControlPart::Button ) )
2536 {
2537 ImplControlValue aControlValue;
2538 ControlState nState = ControlState::NONE;
2539
2540 if ( highlight == 1 ) nState |= ControlState::PRESSED;
2541 if ( highlight == 2 ) nState |= ControlState::ROLLOVER;
2542 if ( bEnabled ) nState |= ControlState::ENABLED;
2543
2544 aControlValue.setTristateVal( bChecked ? ButtonValue::On : ButtonValue::Off );
2545
2546 bNativeOk = rRenderContext.DrawNativeControl( ControlType::Toolbar, ControlPart::Button,
2547 rRect, nState, aControlValue, OUString() );
2548 }
2549
2550 if (!bNativeOk)
2551 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, rRect, bIsWindow ? 3 : highlight,
2552 bChecked, true, bIsWindow, nullptr, 2);
2553}
2554
2555void ToolBox::ImplDrawItem(vcl::RenderContext& rRenderContext, ImplToolItems::size_type nPos, sal_uInt16 nHighlight)
2556{
2557 if (nPos >= mpData->m_aItems.size())
2558 return;
2559
2560 // execute pending paint requests
2561 ImplCheckUpdate();
2562
2563 ImplDisableFlatButtons();
2564
2565 rRenderContext.SetFillColor();
2566
2567 ImplToolItem* pItem = &mpData->m_aItems[nPos];
2568
2569 if (!pItem->mbEnabled)
2570 nHighlight = 0;
2571
2572 // if the rectangle is outside visible area
2573 if (pItem->maRect.IsEmpty())
2574 return;
2575
2576 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2577
2578 // no gradient background for items that have a popup open
2579 bool bHasOpenPopup = mpFloatWin && (mnDownItemId==pItem->mnId);
2580
2581 bool bHighContrastWhite = false;
2582 // check the face color as highcontrast indicator
2583 // because the toolbox itself might have a gradient
2584 if (rStyleSettings.GetFaceColor() == COL_WHITE)
2585 bHighContrastWhite = true;
2586
2587 // Compute buttons area.
2588 Size aBtnSize = pItem->maRect.GetSize();
2589
2590 /* Compute the button/separator rectangle here, we'll need it for
2591 * both the buttons and the separators. */
2592 tools::Rectangle aButtonRect( pItem->maRect.TopLeft(), aBtnSize );
2593 long nOffX = SMALLBUTTON_OFF_NORMAL_X3;
2594 long nOffY = SMALLBUTTON_OFF_NORMAL_Y3;
2595 long nImageOffX = 0;
2596 long nImageOffY = 0;
2597 DrawButtonFlags nStyle = DrawButtonFlags::NONE;
2598
2599 // draw separators in flat style only
2600 if ( (mnOutStyle & TOOLBOX_STYLE_FLAT) &&
2601 (pItem->meType == ToolBoxItemType::SEPARATOR) &&
2602 nPos > 0
2603 )
2604 {
2605 ImplDrawSeparator(rRenderContext, nPos, aButtonRect);
2606 }
2607
2608 // do nothing if item is no button or will be displayed as window
2609 if ( (pItem->meType != ToolBoxItemType::BUTTON) || pItem->mbShowWindow )
2610 return;
2611
2612 if ( pItem->meState == TRISTATE_TRUE )
2613 {
2614 nStyle |= DrawButtonFlags::Checked;
2615 }
2616 else if ( pItem->meState == TRISTATE_INDET )
2617 {
2618 nStyle |= DrawButtonFlags::DontKnow;
2619 }
2620 if ( nHighlight == 1 )
2621 {
2622 nStyle |= DrawButtonFlags::Pressed;
2623 }
2624
2625 if ( mnOutStyle & TOOLBOX_STYLE_FLAT )
2626 {
2627 ImplErase(rRenderContext, pItem->maRect, nHighlight != 0, bHasOpenPopup );
2628 }
2629 else
2630 {
2631 DecorationView aDecoView(&rRenderContext);
2632 aDecoView.DrawButton(aButtonRect, nStyle);
2633 }
2634
2635 nOffX += pItem->maRect.Left();
2636 nOffY += pItem->maRect.Top();
2637
2638 // determine what has to be drawn on the button: image, text or both
2639 bool bImage;
2640 bool bText;
2641 ButtonType tmpButtonType = determineButtonType( pItem, meButtonType ); // default to toolbox setting
2642 pItem->DetermineButtonDrawStyle( tmpButtonType, bImage, bText );
2643
2644 // compute output values
2645 long nBtnWidth = aBtnSize.Width()-SMALLBUTTON_HSIZE7;
2646 long nBtnHeight = aBtnSize.Height()-SMALLBUTTON_VSIZE7;
2647 Size aImageSize;
2648
2649 const bool bDropDown = (pItem->mnBits & ToolBoxItemBits::DROPDOWN) == ToolBoxItemBits::DROPDOWN;
2650 tools::Rectangle aDropDownRect;
2651 if (bDropDown)
2652 aDropDownRect = pItem->GetDropDownRect(mbHorz);
2653
2654 if ( bImage )
2655 {
2656 const Image* pImage = &(pItem->maImage);
2657 aImageSize = pImage->GetSizePixel();
2658
2659 // determine drawing flags
2660 DrawImageFlags nImageStyle = DrawImageFlags::NONE;
2661
2662 if ( !pItem->mbEnabled || !IsEnabled() )
2663 nImageStyle |= DrawImageFlags::Disable;
2664
2665 // #i35563# the dontknow state indicates different states at the same time
2666 // which should not be rendered disabled but normal
2667
2668 // draw the image
2669 nImageOffX = nOffX;
2670 nImageOffY = nOffY;
2671 if ( ( (pItem->mnBits & (ToolBoxItemBits::LEFT|ToolBoxItemBits::DROPDOWN)) || bText )
2672 && ( meTextPosition == ToolBoxTextPosition::Right ) )
2673 {
2674 // left align also to leave space for drop down arrow
2675 // and when drawing text+image
2676 // just center in y, except for vertical (ie rotated text)
2677 if( mbHorz || !bText )
2678 nImageOffY += (nBtnHeight-aImageSize.Height())/2;
2679 }
2680 else
2681 {
2682 nImageOffX += (nBtnWidth-(bDropDown ? aDropDownRect.getWidth() : 0)+SMALLBUTTON_OFF_NORMAL_X3-aImageSize.Width())/2;
2683 if ( meTextPosition == ToolBoxTextPosition::Right )
2684 nImageOffY += (nBtnHeight-aImageSize.Height())/2;
2685 }
2686 if ( nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) )
2687 {
2688 if( bHasOpenPopup )
2689 ImplDrawFloatwinBorder(rRenderContext, pItem);
2690 else
2691 ImplDrawButton(rRenderContext, aButtonRect, nHighlight, pItem->meState == TRISTATE_TRUE,
2692 pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow);
2693
2694 if( nHighlight != 0 )
2695 {
2696 if( bHighContrastWhite )
2697 nImageStyle |= DrawImageFlags::ColorTransform;
2698 }
2699 }
2700 rRenderContext.DrawImage(Point( nImageOffX, nImageOffY ), *pImage, nImageStyle);
2701 }
2702
2703 // draw the text
2704 bool bRotate = false;
2705 if ( bText )
2706 {
2707 const Size aTxtSize(GetCtrlTextWidth(pItem->maText), GetTextHeight());
2708 long nTextOffX = nOffX;
2709 long nTextOffY = nOffY;
2710
2711 // rotate text when vertically docked
2712 vcl::Font aOldFont = rRenderContext.GetFont();
2713 if( pItem->mbVisibleText && !ImplIsFloatingMode() &&
2714 ((meAlign == WindowAlign::Left) || (meAlign == WindowAlign::Right)) )
2715 {
2716 bRotate = true;
2717
2718 vcl::Font aRotateFont = aOldFont;
2719 aRotateFont.SetOrientation( 2700 );
2720
2721 // center horizontally
2722 nTextOffX += aTxtSize.Height();
2723 nTextOffX += (nBtnWidth-aTxtSize.Height())/2;
2724
2725 // add in image offset
2726 if( bImage )
2727 nTextOffY = nImageOffY + aImageSize.Height() + TB_IMAGETEXTOFFSET3;
2728
2729 rRenderContext.SetFont(aRotateFont);
2730 }
2731 else
2732 {
2733 if ( meTextPosition == ToolBoxTextPosition::Right )
2734 {
2735 // center vertically
2736 nTextOffY += (nBtnHeight-aTxtSize.Height())/2;
2737
2738 // add in image offset
2739 if( bImage )
2740 nTextOffX = nImageOffX + aImageSize.Width() + TB_IMAGETEXTOFFSET3;
2741 }
2742 else
2743 {
2744 // center horizontally
2745 nTextOffX += (nBtnWidth-(bDropDown ? aDropDownRect.getWidth() : 0)+SMALLBUTTON_OFF_NORMAL_X3-aTxtSize.Width() - TB_IMAGETEXTOFFSET3)/2;
2746 // set vertical position
2747 nTextOffY += nBtnHeight - aTxtSize.Height();
2748 }
2749 }
2750
2751 // draw selection only if not already drawn during image output (see above)
2752 if ( !bImage && (nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) ) )
2753 {
2754 if( bHasOpenPopup )
2755 ImplDrawFloatwinBorder(rRenderContext, pItem);
2756 else
2757 ImplDrawButton(rRenderContext, pItem->maRect, nHighlight, pItem->meState == TRISTATE_TRUE,
2758 pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow );
2759 }
2760
2761 DrawTextFlags nTextStyle = DrawTextFlags::NONE;
2762 if ( !pItem->mbEnabled )
2763 nTextStyle |= DrawTextFlags::Disable;
2764 rRenderContext.DrawCtrlText( Point( nTextOffX, nTextOffY ), pItem->maText,
2765 0, pItem->maText.getLength(), nTextStyle );
2766 if ( bRotate )
2767 SetFont( aOldFont );
2768 }
2769
2770 // paint optional drop down arrow
2771 if (!bDropDown)
2772 return;
2773
2774 bool bSetColor = true;
2775 if ( !pItem->mbEnabled || !IsEnabled() )
2776 {
2777 bSetColor = false;
2778 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
2779 }
2780
2781 // dropdown only will be painted without inner border
2782 if( (pItem->mnBits & ToolBoxItemBits::DROPDOWNONLY) != ToolBoxItemBits::DROPDOWNONLY )
2783 {
2784 ImplErase(rRenderContext, aDropDownRect, nHighlight != 0, bHasOpenPopup);
2785
2786 if( nHighlight != 0 || (pItem->meState == TRISTATE_TRUE) )
2787 {
2788 if( bHasOpenPopup )
2789 ImplDrawFloatwinBorder(rRenderContext, pItem);
2790 else
2791 ImplDrawButton(rRenderContext, aDropDownRect, nHighlight, pItem->meState == TRISTATE_TRUE,
2792 pItem->mbEnabled && IsEnabled(), false);
2793 }
2794 }
2795 ImplDrawDropdownArrow(rRenderContext, aDropDownRect, bSetColor, bRotate);
2796}
2797
2798void ToolBox::ImplDrawFloatwinBorder(vcl::RenderContext& rRenderContext, ImplToolItem const * pItem)
2799{
2800 if ( pItem->maRect.IsEmpty() )
2801 return;
2802
2803 tools::Rectangle aRect( mpFloatWin->ImplGetItemEdgeClipRect() );
2804 aRect.SetPos( AbsoluteScreenToOutputPixel( aRect.TopLeft() ) );
2805 rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetShadowColor());
2806 Point p1, p2;
2807
2808 p1 = pItem->maRect.TopLeft();
2809 p1.AdjustX( 1 );
2810 p2 = pItem->maRect.TopRight();
2811 p2.AdjustX( -1 );
2812 rRenderContext.DrawLine( p1, p2);
2813 p1 = pItem->maRect.BottomLeft();
2814 p1.AdjustX( 1 );
2815 p2 = pItem->maRect.BottomRight();
2816 p2.AdjustX( -1 );
2817 rRenderContext.DrawLine( p1, p2);
2818
2819 p1 = pItem->maRect.TopLeft();
2820 p1.AdjustY( 1 );
2821 p2 = pItem->maRect.BottomLeft();
2822 p2.AdjustY( -1 );
2823 rRenderContext.DrawLine( p1, p2);
2824 p1 = pItem->maRect.TopRight();
2825 p1.AdjustY( 1 );
2826 p2 = pItem->maRect.BottomRight();
2827 p2.AdjustY( -1 );
2828 rRenderContext.DrawLine( p1, p2);
2829
2830}
2831
2832void ToolBox::ImplFloatControl( bool bStart, FloatingWindow* pFloatWindow )
2833{
2834
2835 if ( bStart )
2836 {
2837 mpFloatWin = pFloatWindow;
2838
2839 // redraw item, to trigger drawing of a special border
2840 InvalidateItem(mnCurPos);
2841
2842 mbDrag = false;
2843 EndTracking();
2844 if (IsMouseCaptured())
2845 ReleaseMouse();
2846 }
2847 else
2848 {
2849 mpFloatWin = nullptr;
2850
2851 // if focus is still in this toolbox, then the floater was opened by keyboard
2852 // draw current item with highlight and keep old state
2853 bool bWasKeyboardActivate = mpData->mbDropDownByKeyboard;
2854
2855 if ( mnCurPos != ITEM_NOTFOUND )
2856 InvalidateItem(mnCurPos);
2857 Deactivate();
2858
2859 if( !bWasKeyboardActivate )
2860 {
2861 mnCurPos = ITEM_NOTFOUND;
2862 mnCurItemId = 0;
2863 mnHighItemId = 0;
2864 }
2865 mnDownItemId = 0;
2866
2867 }
2868}
2869
2870void ToolBox::ShowLine( bool bNext )
2871{
2872 mbFormat = true;
2873
2874 if ( bNext )
2875 mnCurLine++;
2876 else
2877 mnCurLine--;
2878
2879 ImplFormat();
2880}
2881
2882bool ToolBox::ImplHandleMouseMove( const MouseEvent& rMEvt, bool bRepeat )
2883{
2884 Point aMousePos = rMEvt.GetPosPixel();
2885
2886 if ( !mpData )
2887 return false;
2888
2889 // ToolBox active?
2890 if ( mbDrag && mnCurPos != ITEM_NOTFOUND )
2891 {
2892 // is the cursor over the item?
2893 ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
2894 if ( pItem->maRect.IsInside( aMousePos ) )
2895 {
2896 if ( !mnCurItemId )
2897 {
2898 InvalidateItem(mnCurPos);
2899 mnCurItemId = pItem->mnId;
2900 Highlight();
2901 }
2902
2903 if ( (pItem->mnBits & ToolBoxItemBits::REPEAT) && bRepeat )
2904 Select();
2905 }
2906 else
2907 {
2908 if ( mnCurItemId )
2909 {
2910 InvalidateItem(mnCurPos);
2911 mnCurItemId = 0;
2912 InvalidateItem(mnCurPos);
2913 Highlight();
2914 }
2915 }
2916
2917 return true;
2918 }
2919
2920 if ( mbUpper )
2921 {
2922 bool bNewIn = maUpperRect.IsInside( aMousePos );
2923 if ( bNewIn != mbIn )
2924 {
2925 mbIn = bNewIn;
2926 InvalidateSpin(true, false);
2927 }
2928 return true;
2929 }
2930
2931 if ( mbLower )
2932 {
2933 bool bNewIn = maLowerRect.IsInside( aMousePos );
2934 if ( bNewIn != mbIn )
2935 {
2936 mbIn = bNewIn;
2937 InvalidateSpin(false);
2938 }
2939 return true;
2940 }
2941
2942 return false;
2943}
2944
2945bool ToolBox::ImplHandleMouseButtonUp( const MouseEvent& rMEvt, bool bCancel )
2946{
2947 ImplDisableFlatButtons();
2948
2949 if ( !mpData )
2950 return false;
2951
2952 // stop eventual running dropdown timer
2953 if( mnCurPos < mpData->m_aItems.size() &&
2954 (mpData->m_aItems[mnCurPos].mnBits & ToolBoxItemBits::DROPDOWN ) )
2955 {
2956 mpData->maDropdownTimer.Stop();
2957 }
2958
2959 if ( mbDrag )
2960 {
2961 Deactivate();
2962
2963 if ( mbDrag )
2964 mbDrag = false;
2965 else
2966 {
2967 if ( mnCurPos == ITEM_NOTFOUND )
2968 return true;
2969 }
2970
2971 // has mouse been released on top of item?
2972 if( mnCurPos < mpData->m_aItems.size() )
2973 {
2974 ImplToolItem* pItem = &mpData->m_aItems[mnCurPos];
2975 if ( pItem->maRect.IsInside( rMEvt.GetPosPixel() ) )
2976 {
2977 mnCurItemId = pItem->mnId;
2978 if ( !bCancel )
2979 {
2980 // execute AutoCheck if required
2981 if ( pItem->mnBits & ToolBoxItemBits::AUTOCHECK )
2982 {
2983 if ( pItem->mnBits & ToolBoxItemBits::RADIOCHECK )
2984 {
2985 if ( pItem->meState != TRISTATE_TRUE )
2986 SetItemState( pItem->mnId, TRISTATE_TRUE );
2987 }
2988 else
2989 {
2990 if ( pItem->meState != TRISTATE_TRUE )
2991 pItem->meState = TRISTATE_TRUE;
2992 else
2993 pItem->meState = TRISTATE_FALSE;
2994 }
2995 }
2996
2997 // do not call Select when Repeat is active, as in this
2998 // case that was triggered already in MouseButtonDown
2999 if ( !(pItem->mnBits & ToolBoxItemBits::REPEAT) )
3000 {
3001 // prevent from being destroyed in the select handler
3002 VclPtr<vcl::Window> xWindow = this;
3003 Select();
3004 if ( xWindow->IsDisposed() )
3005 return true;
3006 }
3007 }
3008
3009 {
3010 }
3011
3012 // Items not destroyed, in Select handler
3013 if ( mnCurItemId )
3014 {
3015 // Get current pos for the case that items are inserted/removed
3016 // in the toolBox
3017 mnCurPos = GetItemPos( mnCurItemId );
3018 if ( mnCurPos != ITEM_NOTFOUND )
3019 {
3020 InvalidateItem(mnCurPos);
3021 Flush();
3022 }
3023 }
3024 }
3025 }
3026
3027 mnCurPos = ITEM_NOTFOUND;
3028 mnCurItemId = 0;
3029 mnDownItemId = 0;
3030 mnMouseModifier = 0;
3031 return true;
3032 }
3033 else if ( mbUpper || mbLower )
3034 {
3035 if ( mbIn )
3036 ShowLine( !mbUpper );
3037 mbUpper = false;
3038 mbLower = false;
3039 mbIn = false;
3040 InvalidateSpin();
3041 return true;
3042 }
3043
3044 return false;
3045}
3046
3047void ToolBox::MouseMove( const MouseEvent& rMEvt )
3048{
3049 // pressing a modifier generates synthetic mouse moves
3050 // ignore it if keyboard selection is active
3051 if( HasFocus() && ( rMEvt.GetMode() & MouseEventModifiers::MODIFIERCHANGED ) )
3052 return;
3053
3054 if ( ImplHandleMouseMove( rMEvt ) )
3055 return;
3056
3057 ImplDisableFlatButtons();
3058
3059 Point aMousePos = rMEvt.GetPosPixel();
3060
3061 // only highlight when the focus is not inside a child window of a toolbox
3062 // eg, in an edit control
3063 // and do not highlight when focus is in a different toolbox
3064 bool bDrawHotSpot = true;
3065 vcl::Window *pFocusWin = Application::GetFocusWindow();
3066
3067 bool bFocusWindowIsAToolBoxChild = false;
3068 if (pFocusWin)
3069 {
3070 vcl::Window *pWin = pFocusWin->GetParent();
3071 while (pWin)
3072 {
3073 if(pWin->ImplGetWindowImpl()->mbToolBox)
3074 {
3075 bFocusWindowIsAToolBoxChild = true;
3076 break;
3077 }
3078 pWin = pWin->GetParent();
3079 }
3080 }
3081
3082 if( bFocusWindowIsAToolBoxChild || (pFocusWin && pFocusWin->ImplGetWindowImpl()->mbToolBox && pFocusWin != this) )
3083 bDrawHotSpot = false;
3084
3085 if ( mbDragging )
3086 {
3087 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3088 pMgr->Dragging( aMousePos );
3089 return;
3090 }
3091
3092 PointerStyle eStyle = PointerStyle::Arrow;
3093
3094 // change mouse cursor over drag area
3095 ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
3096 if( pWrapper && pWrapper->GetDragArea().IsInside( rMEvt.GetPosPixel() ) )
3097 eStyle = PointerStyle::Move;
3098
3099 if ( (mnWinStyle & TB_WBLINESIZING(WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL)) == TB_WBLINESIZING(WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL) )
3100 {
3101 if ( rMEvt.GetMode() & MouseEventModifiers::SIMPLEMOVE )
3102 {
3103 sal_uInt16 nLinePtr = ImplTestLineSize( rMEvt.GetPosPixel() );
3104 if ( nLinePtr & DOCK_LINEHSIZE(sal_uInt16(0x0001)) )
3105 {
3106 if ( meAlign == WindowAlign::Left )
3107 eStyle = PointerStyle::WindowESize;
3108 else
3109 eStyle = PointerStyle::WindowWSize;
3110 }
3111 else if ( nLinePtr & DOCK_LINEVSIZE(sal_uInt16(0x0002)) )
3112 {
3113 if ( meAlign == WindowAlign::Top )
3114 eStyle = PointerStyle::WindowSSize;
3115 else
3116 eStyle = PointerStyle::WindowNSize;
3117 }
3118 }
3119 }
3120
3121 if ( bDrawHotSpot && ( (mnOutStyle & TOOLBOX_STYLE_FLAT) || !mnOutStyle ) )
3122 {
3123 bool bClearHigh = true;
3124 if ( !rMEvt.IsLeaveWindow() && (mnCurPos == ITEM_NOTFOUND) )
3125 {
3126 ImplToolItems::size_type nTempPos = 0;
3127 for (auto const& item : mpData->m_aItems)
3128 {
3129 if ( item.maRect.IsInside( aMousePos ) )
3130 {
3131 if ( (item.meType == ToolBoxItemType::BUTTON) && item.mbEnabled )
3132 {
3133 if ( !mnOutStyle || (mnOutStyle & TOOLBOX_STYLE_FLAT) )
3134 {
3135 bClearHigh = false;
3136 if ( mnHighItemId != item.mnId )
3137 {
3138 if ( mnHighItemId )
3139 {
3140 ImplHideFocus();
3141 ImplToolItems::size_type nPos = GetItemPos( mnHighItemId );
3142 InvalidateItem(nPos);
3143 CallEventListeners( VclEventId::ToolboxHighlightOff, reinterpret_cast< void* >( nPos ) );
3144 }
3145 if ( mpData->mbMenubuttonSelected )
3146 {
3147 // remove highlight from menubutton
3148 InvalidateMenuButton();
3149 }
3150 mnHighItemId = item.mnId;
3151 InvalidateItem(nTempPos);
3152 ImplShowFocus();
3153 CallEventListeners( VclEventId::ToolboxHighlight );
3154 }
3155 }
3156 }
3157 break;
3158 }
3159 ++nTempPos;
3160 }
3161 }
3162
3163 // only clear highlight when focus is not in toolbar
3164 bool bMenuButtonHit = mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) && ImplHasClippedItems();
3165 if ( !HasFocus() && (bClearHigh || bMenuButtonHit) )
3166 {
3167 if ( !bMenuButtonHit && mpData->mbMenubuttonSelected )
3168 {
3169 // remove highlight from menubutton
3170 InvalidateMenuButton();
3171 }
3172
3173 if( mnHighItemId )
3174 {
3175 ImplToolItems::size_type nClearPos = GetItemPos( mnHighItemId );
3176 if ( nClearPos != ITEM_NOTFOUND )
3177 {
3178 InvalidateItem(nClearPos);
3179 if( nClearPos != mnCurPos )
3180 CallEventListeners( VclEventId::ToolboxHighlightOff, reinterpret_cast< void* >( nClearPos ) );
3181 }
3182 ImplHideFocus();
3183 mnHighItemId = 0;
3184 }
3185
3186 if( bMenuButtonHit )
3187 {
3188 InvalidateMenuButton();
3189 }
3190 }
3191 }
3192
3193 if ( meLastStyle != eStyle )
3194 {
3195 meLastStyle = eStyle;
3196 SetPointer( eStyle );
3197 }
3198
3199 DockingWindow::MouseMove( rMEvt );
3200}
3201
3202void ToolBox::MouseButtonDown( const MouseEvent& rMEvt )
3203{
3204 // only trigger toolbox for left mouse button and when
3205 // we're not in normal operation
3206 if ( rMEvt.IsLeft() && !mbDrag && (mnCurPos == ITEM_NOTFOUND) )
3207 {
3208 // call activate already here, as items could
3209 // be exchanged
3210 Activate();
3211
3212 // update ToolBox here, such that user knows it
3213 if ( mbFormat )
3214 {
3215 ImplFormat();
3216 PaintImmediately();
3217 }
3218
3219 Point aMousePos = rMEvt.GetPosPixel();
3220 ImplToolItems::size_type i = 0;
3221 ImplToolItems::size_type nNewPos = ITEM_NOTFOUND;
3222
3223 // search for item that was clicked
3224 for (auto const& item : mpData->m_aItems)
3225 {
3226 // is this the item?
3227 if ( item.maRect.IsInside( aMousePos ) )
3228 {
3229 // do nothing if it is a separator or
3230 // if the item has been disabled
3231 if ( (item.meType == ToolBoxItemType::BUTTON) &&
3232 !item.mbShowWindow )
3233 nNewPos = i;
3234
3235 break;
3236 }
3237
3238 i++;
3239 }
3240
3241 // item found
3242 if ( nNewPos != ITEM_NOTFOUND )
3243 {
3244 if ( !mpData->m_aItems[nNewPos].mbEnabled )
3245 {
3246 Deactivate();
3247 return;
3248 }
3249
3250 // update actual data
3251 StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
3252 mnCurPos = i;
3253 mnCurItemId = mpData->m_aItems[nNewPos].mnId;
3254 mnDownItemId = mnCurItemId;
3255 mnMouseModifier = rMEvt.GetModifier();
3256 if ( mpData->m_aItems[nNewPos].mnBits & ToolBoxItemBits::REPEAT )
3257 nTrackFlags |= StartTrackingFlags::ButtonRepeat;
3258
3259 // update bDrag here, as it is evaluated in the EndSelection
3260 mbDrag = true;
3261
3262 // on double-click: only call the handler, but do so before the button
3263 // is hit, as in the handler dragging
3264 // can be terminated
3265 if ( rMEvt.GetClicks() == 2 )
3266 DoubleClick();
3267
3268 if ( mbDrag )
3269 {
3270 InvalidateItem(mnCurPos);
3271 Highlight();
3272 }
3273
3274 // was dropdown arrow pressed
3275 if( mpData->m_aItems[nNewPos].mnBits & ToolBoxItemBits::DROPDOWN )
3276 {
3277 if( ( (mpData->m_aItems[nNewPos].mnBits & ToolBoxItemBits::DROPDOWNONLY) == ToolBoxItemBits::DROPDOWNONLY)
3278 || mpData->m_aItems[nNewPos].GetDropDownRect( mbHorz ).IsInside( aMousePos ))
3279 {
3280 // dropdownonly always triggers the dropdown handler, over the whole button area
3281
3282 // the drop down arrow should not trigger the item action
3283 mpData->mbDropDownByKeyboard = false;
3284 mpData->maDropdownClickHdl.Call( this );
3285
3286 // do not reset data if the dropdown handler opened a floating window
3287 // see ImplFloatControl()
3288 if( !mpFloatWin )
3289 {
3290 // no floater was opened
3291 Deactivate();
3292 InvalidateItem(mnCurPos);
3293
3294 mnCurPos = ITEM_NOTFOUND;
3295 mnCurItemId = 0;
3296 mnDownItemId = 0;
3297 mnMouseModifier = 0;
3298 mnHighItemId = 0;
3299 }
3300 return;
3301 }
3302 else // activate long click timer
3303 mpData->maDropdownTimer.Start();
3304 }
3305
3306 // call Click handler
3307 if ( rMEvt.GetClicks() != 2 )
3308 Click();
3309
3310 // also call Select handler at repeat
3311 if ( nTrackFlags & StartTrackingFlags::ButtonRepeat )
3312 Select();
3313
3314 // if the actions was not aborted in Click handler
3315 if ( mbDrag )
3316 StartTracking( nTrackFlags );
3317
3318 // if mouse was clicked over an item we
3319 // can abort here
3320 return;
3321 }
3322
3323 Deactivate();
3324
3325 // menu button hit ?
3326 if( mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) && ImplHasClippedItems() )
3327 {
3328 if ( maMenuButtonHdl.IsSet() )
3329 maMenuButtonHdl.Call( this );
3330 else
3331 ExecuteCustomMenu( mpData->maMenubuttonItem.maRect );
3332 return;
3333 }
3334
3335 // check scroll- and next-buttons here
3336 if ( maUpperRect.IsInside( aMousePos ) )
3337 {
3338 if ( mnCurLine > 1 )
3339 {
3340 StartTracking();
3341 mbUpper = true;
3342 mbIn = true;
3343 InvalidateSpin(true, false);
3344 }
3345 return;
3346 }
3347 if ( maLowerRect.IsInside( aMousePos ) )
3348 {
3349 if ( mnCurLine+mnVisLines-1 < mnCurLines )
3350 {
3351 StartTracking();
3352 mbLower = true;
3353 mbIn = true;
3354 InvalidateSpin(false);
3355 }
3356 return;
3357 }
3358
3359 // Linesizing testen
3360 if ( (mnWinStyle & TB_WBLINESIZING(WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL)) == TB_WBLINESIZING(WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL) )
3361 {
3362 sal_uInt16 nLineMode = ImplTestLineSize( aMousePos );
3363 if ( nLineMode )
3364 {
3365 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3366
3367 // call handler, such that we can set the
3368 // dock rectangles
3369 StartDocking();
3370
3371 Point aPos = GetParent()->OutputToScreenPixel( GetPosPixel() );
3372 Size aSize = GetSizePixel();
3373 aPos = ScreenToOutputPixel( aPos );
3374
3375 // start dragging
3376 pMgr->StartDragging( this, aMousePos, tools::Rectangle( aPos, aSize ),
3377 nLineMode );
3378 return;
3379 }
3380 }
3381
3382 // no item, then only click or double click
3383 if ( rMEvt.GetClicks() == 2 )
3384 DoubleClick();
3385 else
3386 Click();
3387 }
3388
3389 if ( !mbDrag && (mnCurPos == ITEM_NOTFOUND) )
3390 DockingWindow::MouseButtonDown( rMEvt );
3391}
3392
3393void ToolBox::MouseButtonUp( const MouseEvent& rMEvt )
3394{
3395 if ( ImplHandleMouseButtonUp( rMEvt ) )
3396 return;
3397
3398 if ( mbDragging && rMEvt.IsLeft() )
3399 {
3400 ImplTBDragMgr* pMgr = ImplGetTBDragMgr();
3401 pMgr->EndDragging();
3402 return;
3403 }
3404
3405 DockingWindow::MouseButtonUp( rMEvt );
3406}
3407
3408void ToolBox::Tracking( const TrackingEvent& rTEvt )
3409{
3410 VclPtr<vcl::Window> xWindow = this;
3411
3412 if ( rTEvt.IsTrackingEnded() )
3413 ImplHandleMouseButtonUp( rTEvt.GetMouseEvent(), rTEvt.IsTrackingCanceled() );
3414 else
3415 ImplHandleMouseMove( rTEvt.GetMouseEvent(), rTEvt.IsTrackingRepeat() );
3416
3417 if ( xWindow->IsDisposed() )
3418 // toolbox was deleted
3419 return;
3420 DockingWindow::Tracking( rTEvt );
3421}
3422
3423void ToolBox::InvalidateItem(ImplToolItems::size_type nPosition)
3424{
3425 if (mpData && nPosition < mpData->m_aItems.size())
3426 {
3427 ImplToolItem* pItem = &mpData->m_aItems[nPosition];
3428 Invalidate(pItem->maRect);
3429 }
3430}
3431
3432void ToolBox::InvalidateMenuButton()
3433{
3434 if (!mpData->maMenubuttonItem.maRect.IsEmpty())
3435 Invalidate(mpData->maMenubuttonItem.maRect);
3436}
3437
3438void ToolBox::InvalidateSpin(bool bUpperIn, bool bLowerIn)
3439{
3440 if (bUpperIn && !maUpperRect.IsEmpty())
3441 Invalidate(maUpperRect);
3442
3443 if (bLowerIn && !maLowerRect.IsEmpty())
3444 Invalidate(maLowerRect);
3445}
3446
3447void ToolBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rPaintRect)
3448{
3449 if( mpData->mbIsPaintLocked )
3450 return;
3451
3452 if (rPaintRect == tools::Rectangle(0, 0, mnDX-1, mnDY-1))
3453 mbFullPaint = true;
3454 ImplFormat();
3455 mbFullPaint = false;
3456
3457 ImplDrawBackground(rRenderContext, rPaintRect);
3458
3459 if ( (mnWinStyle & WB_BORDER) && !ImplIsFloatingMode() )
3460 ImplDrawBorder(rRenderContext);
3461
3462 if( !ImplIsFloatingMode() )
3463 ImplDrawGrip(rRenderContext);
3464
3465 ImplDrawMenuButton(rRenderContext, mpData->mbMenubuttonSelected);
3466
3467 // draw SpinButtons
3468 if (mnWinStyle & WB_SCROLL)
3469 {
3470 if (mnCurLines > mnLines)
3471 ImplDrawSpin(rRenderContext);
3472 }
3473
3474 // draw buttons
3475 ImplToolItems::size_type nHighPos;
3476 if ( mnHighItemId )
3477 nHighPos = GetItemPos( mnHighItemId );
3478 else
3479 nHighPos = ITEM_NOTFOUND;
3480
3481 ImplToolItems::size_type nCount = mpData->m_aItems.size();
3482 for( ImplToolItems::size_type i = 0; i < nCount; i++ )
3483 {
3484 ImplToolItem* pItem = &mpData->m_aItems[i];
3485
3486 // only draw when the rectangle is in the draw rectangle
3487 if ( !pItem->maRect.IsEmpty() && rPaintRect.IsOver( pItem->maRect ) )
3488 {
3489 sal_uInt16 nHighlight = 0;
3490 if ( i == mnCurPos )
3491 nHighlight = 1;
3492 else if ( i == nHighPos )
3493 nHighlight = 2;
3494 ImplDrawItem(rRenderContext, i, nHighlight);
3495 }
3496 }
3497 ImplShowFocus();
3498}
3499
3500void ToolBox::Resize()
3501{
3502 Size aSize = GetOutputSizePixel();
3503 // #i31422# some WindowManagers send (0,0) sizes when
3504 // switching virtual desktops - ignore this and avoid reformatting
3505 if( !aSize.Width() && !aSize.Height() )
3506 return;
3507
3508 long nOldDX = mnDX;
3509 long nOldDY = mnDY;
3510 mnDX = aSize.Width();
3511 mnDY = aSize.Height();
3512
3513 mnLastResizeDY = 0;
3514
3515 // invalidate everything to have gradient backgrounds properly drawn
3516 Invalidate();
3517
3518 // If we have any expandable entries, then force a reformat first using
3519 // their optimal sizes, then share out the excess space evenly across those
3520 // expandables and reformat again
3521 std::vector<size_t> aExpandables;
3522 for (size_t i = 0; i < mpData->m_aItems.size(); ++i)
3523 {
3524 if (mpData->m_aItems[i].mbExpand)
3525 {
3526 vcl::Window *pWindow = mpData->m_aItems[i].mpWindow;
3527 SAL_INFO_IF(!pWindow, "vcl.layout", "only tabitems with window supported at the moment")do { if (true && (!pWindow)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_INFO, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "only tabitems with window supported at the moment"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "3527" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "only tabitems with window supported at the moment"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "only tabitems with window supported at the moment"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "3527" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "only tabitems with window supported at the moment"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "3527" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "only tabitems with window supported at the moment"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "only tabitems with window supported at the moment"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "3527" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3528 if (!pWindow)
3529 continue;
3530 Size aWinSize(pWindow->GetSizePixel());
3531 Size aPrefSize(pWindow->get_preferred_size());
3532 aWinSize.setWidth( aPrefSize.Width() );
3533 pWindow->SetSizePixel(aWinSize);
3534 aExpandables.push_back(i);
3535 }
3536 }
3537
3538 // re-format or re-draw
3539 if ( mbScroll || !aExpandables.empty() )
3540 {
3541 if ( !mbFormat || !aExpandables.empty() )
3542 {
3543 mbFormat = true;
3544 if( IsReallyVisible() || !aExpandables.empty() )
3545 {
3546 ImplFormat(true);
3547
3548 if (!aExpandables.empty())
3549 {
3550 //Get how big the optimal size is
3551 tools::Rectangle aBounds;
3552 for (const ImplToolItem & rItem : mpData->m_aItems)
3553 {
3554 aBounds.Union( rItem.maRect );
3555 }
3556
3557 auto nOptimalWidth = aBounds.GetWidth();
3558 auto nDiff = aSize.Width() - nOptimalWidth;
3559 decltype(nDiff) nExpandablesSize = aExpandables.size();
3560 nDiff /= nExpandablesSize;
3561
3562 //share out the diff from optimal to real across
3563 //expandable entries
3564 for (size_t nIndex : aExpandables)
3565 {
3566 vcl::Window *pWindow = mpData->m_aItems[nIndex].mpWindow;
3567 Size aWinSize(pWindow->GetSizePixel());
3568 Size aPrefSize(pWindow->get_preferred_size());
3569 aWinSize.setWidth( aPrefSize.Width() + nDiff );
3570 pWindow->SetSizePixel(aWinSize);
3571 }
3572
3573 //now reformat with final sizes
3574 mbFormat = true;
3575 ImplFormat(true);
3576 }
3577 }
3578 }
3579 }
3580
3581 // redraw border
3582 if ( !(mnWinStyle & WB_BORDER) )
3583 return;
3584
3585 // as otherwise, when painting we might think we have to re-draw everything
3586 if ( mbFormat && IsReallyVisible() )
3587 Invalidate();
3588 else
3589 {
3590 if ( mnRightBorder )
3591 {
3592 if ( nOldDX > mnDX )
3593 Invalidate( tools::Rectangle( mnDX-mnRightBorder-1, 0, mnDX, mnDY ) );
3594 else
3595 Invalidate( tools::Rectangle( nOldDX-mnRightBorder-1, 0, nOldDX, nOldDY ) );
3596 }
3597
3598 if ( mnBottomBorder )
3599 {
3600 if ( nOldDY > mnDY )
3601 Invalidate( tools::Rectangle( 0, mnDY-mnBottomBorder-1, mnDX, mnDY ) );
3602 else
3603 Invalidate( tools::Rectangle( 0, nOldDY-mnBottomBorder-1, nOldDX, nOldDY ) );
3604 }
3605 }
3606}
3607
3608namespace
3609{
3610 bool DispatchableCommand(const OUString& rName)
3611 {
3612 return rName.startsWith(".uno") ||
3613 rName.startsWith("slot:") ||
3614 rName.startsWith("macro:") ||
3615 rName.startsWith("vnd.sun.star.script");
3616 }
3617}
3618
3619const OUString& ToolBox::ImplGetHelpText( sal_uInt16 nItemId ) const
3620{
3621 ImplToolItem* pItem = ImplGetItem( nItemId );
3622
3623 assert( pItem )(static_cast <bool> (pItem) ? void (0) : __assert_fail (
"pItem", "/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
, 3623, __extension__ __PRETTY_FUNCTION__))
;
3624
3625 if ( pItem->maHelpText.isEmpty() && ( !pItem->maHelpId.isEmpty() || pItem->maCommandStr.getLength() ))
3626 {
3627 Help* pHelp = Application::GetHelp();
3628 if ( pHelp )
3629 {
3630 if (DispatchableCommand(pItem->maCommandStr))
3631 pItem->maHelpText = pHelp->GetHelpText( pItem->maCommandStr, this );
3632 if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() )
3633 pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)) ), this );
3634 }
3635 }
3636
3637 return pItem->maHelpText;
3638}
3639
3640void ToolBox::RequestHelp( const HelpEvent& rHEvt )
3641{
3642 sal_uInt16 nItemId;
3643 Point aHelpPos;
3644
3645 if( !rHEvt.KeyboardActivated() )
3646 {
3647 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
3648 aHelpPos = rHEvt.GetMousePosPixel();
3649 }
3650 else
3651 {
3652 if( !mnHighItemId )
3653 return;
3654 else
3655 nItemId = mnHighItemId;
3656 tools::Rectangle aRect( GetItemRect( nItemId ) );
3657 if( aRect.IsEmpty() )
3658 return;
3659 else
3660 aHelpPos = OutputToScreenPixel( aRect.Center() );
3661 }
3662
3663 if ( nItemId )
3664 {
3665 if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) )
3666 {
3667 // get rectangle
3668 tools::Rectangle aTempRect = GetItemRect( nItemId );
3669 Point aPt = OutputToScreenPixel( aTempRect.TopLeft() );
3670 aTempRect.SetLeft( aPt.X() );
3671 aTempRect.SetTop( aPt.Y() );
3672 aPt = OutputToScreenPixel( aTempRect.BottomRight() );
3673 aTempRect.SetRight( aPt.X() );
3674 aTempRect.SetBottom( aPt.Y() );
3675
3676 // get text and display it
3677 OUString aStr = GetQuickHelpText( nItemId );
3678 if (aStr.isEmpty())
3679 aStr = MnemonicGenerator::EraseAllMnemonicChars( GetItemText( nItemId ) );
3680 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
3681 {
3682 const OUString& rHelpStr = GetHelpText( nItemId );
3683 if (!rHelpStr.isEmpty())
3684 aStr = rHelpStr;
3685 Help::ShowBalloon( this, aHelpPos, aTempRect, aStr );
3686 }
3687 else
3688 Help::ShowQuickHelp( this, aTempRect, aStr, QuickHelpFlags::CtrlText );
3689 return;
3690 }
3691 }
3692
3693 DockingWindow::RequestHelp( rHEvt );
3694}
3695
3696bool ToolBox::EventNotify( NotifyEvent& rNEvt )
3697{
3698 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
3699 {
3700 KeyEvent aKEvt = *rNEvt.GetKeyEvent();
3701 vcl::KeyCode aKeyCode = aKEvt.GetKeyCode();
3702 sal_uInt16 nKeyCode = aKeyCode.GetCode();
3703 switch( nKeyCode )
3704 {
3705 case KEY_TAB:
3706 {
3707 // internal TAB cycling only if parent is not a dialog or if we are the only child
3708 // otherwise the dialog control will take over
3709 vcl::Window *pParent = ImplGetParent();
3710 bool bOldSchoolContainer =
3711 ((pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL &&
3712 pParent->GetChildCount() != 1);
3713 bool bNoTabCycling = bOldSchoolContainer || isContainerWindow(pParent);
3714
3715 if( bNoTabCycling )
3716 return DockingWindow::EventNotify( rNEvt );
3717 else if( ImplChangeHighlightUpDn( aKeyCode.IsShift() , bNoTabCycling ) )
3718 return true;
3719 else
3720 return DockingWindow::EventNotify( rNEvt );
3721 }
3722 default:
3723 break;
3724 }
3725 }
3726 else if( rNEvt.GetType() == MouseNotifyEvent::GETFOCUS )
3727 {
3728 if( rNEvt.GetWindow() == this )
3729 {
3730 // the toolbar itself got the focus
3731 if( mnLastFocusItemId != 0 || mpData->mbMenubuttonWasLastSelected )
3732 {
3733 // restore last item
3734 if( mpData->mbMenubuttonWasLastSelected )
3735 {
3736 ImplChangeHighlight( nullptr );
3737 mpData->mbMenubuttonSelected = true;
3738 InvalidateMenuButton();
3739 }
3740 else
3741 {
3742 ImplChangeHighlight( ImplGetItem( mnLastFocusItemId ) );
3743 mnLastFocusItemId = 0;
3744 }
3745 }
3746 else if( (GetGetFocusFlags() & (GetFocusFlags::Backward|GetFocusFlags::Tab) ) == (GetFocusFlags::Backward|GetFocusFlags::Tab))
3747 // Shift-TAB was pressed in the parent
3748 ImplChangeHighlightUpDn( false );
3749 else
3750 ImplChangeHighlightUpDn( true );
3751
3752 mnLastFocusItemId = 0;
3753
3754 return true;
3755 }
3756 else
3757 {
3758 // a child window got the focus so update current item to
3759 // allow for proper lose focus handling in keyboard navigation
3760 for (auto const& item : mpData->m_aItems)
3761 {
3762 if ( item.mbVisible )
3763 {
3764 if ( item.mpWindow && item.mpWindow->ImplIsWindowOrChild( rNEvt.GetWindow() ) )
3765 {
3766 mnHighItemId = item.mnId;
3767 break;
3768 }
3769 }
3770 }
3771 return DockingWindow::EventNotify( rNEvt );
3772 }
3773 }
3774 else if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
3775 {
3776 // deselect
3777 ImplHideFocus();
3778 mpData->mbMenubuttonWasLastSelected = false;
3779 mnHighItemId = 0;
3780 mnCurPos = ITEM_NOTFOUND;
3781 }
3782
3783 return DockingWindow::EventNotify( rNEvt );
3784}
3785
3786void ToolBox::Command( const CommandEvent& rCEvt )
3787{
3788 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
3789 {
3790 if ( (mnCurLine > 1) || (mnCurLine+mnVisLines-1 < mnCurLines) )
3791 {
3792 const CommandWheelData* pData = rCEvt.GetWheelData();
3793 if ( pData->GetMode() == CommandWheelMode::SCROLL )
3794 {
3795 if ( (mnCurLine > 1) && (pData->GetDelta() > 0) )
3796 ShowLine( false );
3797 else if ( (mnCurLine+mnVisLines-1 < mnCurLines) && (pData->GetDelta() < 0) )
3798 ShowLine( true );
3799 InvalidateSpin();
3800 return;
3801 }
3802 }
3803 }
3804 else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
3805 {
3806 ExecuteCustomMenu( tools::Rectangle( rCEvt.GetMousePosPixel(), rCEvt.GetMousePosPixel() ) );
3807 return;
3808 }
3809
3810 DockingWindow::Command( rCEvt );
3811}
3812
3813void ToolBox::StateChanged( StateChangedType nType )
3814{
3815 DockingWindow::StateChanged( nType );
3816
3817 if ( nType == StateChangedType::InitShow )
3818 ImplFormat();
3819 else if ( nType == StateChangedType::Enable )
3820 ImplUpdateItem();
3821 else if ( nType == StateChangedType::UpdateMode )
3822 {
3823 if ( IsUpdateMode() )
3824 Invalidate();
3825 }
3826 else if ( (nType == StateChangedType::Zoom) ||
3827 (nType == StateChangedType::ControlFont) )
3828 {
3829 mbCalc = true;
3830 mbFormat = true;
3831 ImplInitSettings( true, false, false );
3832 Invalidate();
3833 }
3834 else if ( nType == StateChangedType::ControlForeground )
3835 {
3836 ImplInitSettings( false, true, false );
3837 Invalidate();
3838 }
3839 else if ( nType == StateChangedType::ControlBackground )
3840 {
3841 ImplInitSettings( false, false, true ); // font, foreground, background
3842 Invalidate();
3843 }
3844
3845 maStateChangedHandler.Call( &nType );
3846}
3847
3848void ToolBox::DataChanged( const DataChangedEvent& rDCEvt )
3849{
3850 DockingWindow::DataChanged( rDCEvt );
3851
3852 if ( (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
3853 (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
3854 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
3855 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
3856 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
3857 {
3858 mbCalc = true;
3859 mbFormat = true;
3860 ImplInitSettings( true, true, true );
3861 Invalidate();
3862 }
3863
3864 maDataChangedHandler.Call( &rDCEvt );
3865}
3866
3867void ToolBox::statusChanged( const css::frame::FeatureStateEvent& Event )
3868{
3869 // Update image mirroring/rotation
3870 if ( Event.FeatureURL.Complete != ".uno:ImageOrientation" )
3871 return;
3872
3873 SfxImageItem aItem( 1 );
3874 aItem.PutValue( Event.State, 0 );
3875
3876 mbImagesMirrored = aItem.IsMirrored();
3877 mnImagesRotationAngle = aItem.GetRotation();
3878
3879 // update image orientation
3880 OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(mpStatusListener->getFrame()));
3881 for (auto const& item : mpData->m_aItems)
3882 {
3883 if (vcl::CommandInfoProvider::IsMirrored(item.maCommandStr, aModuleName))
3884 SetItemImageMirrorMode(item.mnId, mbImagesMirrored);
3885 if (vcl::CommandInfoProvider::IsRotated(item.maCommandStr, aModuleName))
3886 SetItemImageAngle(item.mnId, mnImagesRotationAngle);
3887 }
3888}
3889
3890void ToolBox::SetStyle(WinBits nNewStyle)
3891{
3892 mnWinStyle = nNewStyle;
3893 if (!ImplIsFloatingMode())
3894 {
3895 bool bOldScroll = mbScroll;
3896 mbScroll = (mnWinStyle & WB_SCROLL) != 0;
3897 if (mbScroll != bOldScroll)
3898 {
3899 mbFormat = true;
3900 ImplFormat();
3901 }
3902 }
3903}
3904
3905void ToolBox::ToggleFloatingMode()
3906{
3907 DockingWindow::ToggleFloatingMode();
3908
3909 if (!mpData)
3910 return;
3911
3912 bool bOldHorz = mbHorz;
3913
3914 if ( ImplIsFloatingMode() )
3915 {
3916 mbHorz = true;
3917 meAlign = WindowAlign::Top;
3918 mbScroll = true;
3919
3920 if( bOldHorz != mbHorz )
3921 mbCalc = true; // orientation was changed !
3922
3923 ImplSetMinMaxFloatSize();
3924 SetOutputSizePixel( ImplCalcFloatSize( mnFloatLines ) );
3925 }
3926 else
3927 {
3928 mbScroll = (mnWinStyle & WB_SCROLL) != 0;
3929 if ( (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom) )
3930 mbHorz = true;
3931 else
3932 mbHorz = false;
3933
3934 // set focus back to document
3935 ImplGetFrameWindow()->GetWindow( GetWindowType::Client )->GrabFocus();
3936 }
3937
3938 if( bOldHorz != mbHorz )
3939 {
3940 // if orientation changes, the toolbox has to be initialized again
3941 // to update the direction of the gradient
3942 mbCalc = true;
3943 ImplInitSettings( true, true, true );
3944 }
3945
3946 mbFormat = true;
3947 ImplFormat();
3948}
3949
3950void ToolBox::StartDocking()
3951{
3952 meDockAlign = meAlign;
3953 mnDockLines = mnLines;
3954 mbLastFloatMode = ImplIsFloatingMode();
3955 DockingWindow::StartDocking();
3956}
3957
3958bool ToolBox::Docking( const Point& rPos, tools::Rectangle& rRect )
3959{
3960 // do nothing during dragging, it was calculated before
3961 if ( mbDragging )
3962 return false;
3963
3964 bool bFloatMode = false;
3965
3966 DockingWindow::Docking( rPos, rRect );
3967
3968 // if the mouse is outside the area, it can only become a floating window
3969 tools::Rectangle aDockingRect( rRect );
3970 if ( !ImplIsFloatingMode() )
3971 {
3972 // don't use tracking rectangle for alignment check, because it will be too large
3973 // to get a floating mode as result - switch to floating size
3974 // so the calculation only depends on the position of the rectangle, not the current
3975 // docking state of the window
3976 ImplToolItems::size_type nTemp = 0;
3977 aDockingRect.SetSize( ImplCalcFloatSize( nTemp ) );
3978
3979 // in this mode docking is never done by keyboard, so it's OK to use the mouse position
3980 aDockingRect.SetPos( ImplGetFrameWindow()->GetPointerPosPixel() );
3981 }
3982
3983 bFloatMode = true;
3984
3985 meDockAlign = meAlign;
3986 if ( !mbLastFloatMode )
3987 {
3988 ImplToolItems::size_type nTemp = 0;
3989 aDockingRect.SetSize( ImplCalcFloatSize( nTemp ) );
3990 }
3991
3992 rRect = aDockingRect;
3993 mbLastFloatMode = bFloatMode;
3994
3995 return bFloatMode;
3996}
3997
3998void ToolBox::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
3999{
4000 if ( !IsDockingCanceled() )
4001 {
4002 if ( mnLines != mnDockLines )
4003 SetLineCount( mnDockLines );
4004 if ( meAlign != meDockAlign )
4005 SetAlign( meDockAlign );
4006 }
4007 if ( bFloatMode || (bFloatMode != ImplIsFloatingMode()) )
4008 DockingWindow::EndDocking( rRect, bFloatMode );
4009}
4010
4011void ToolBox::Resizing( Size& rSize )
4012{
4013 ImplToolItems::size_type nCalcLines;
4014 ImplToolItems::size_type nTemp;
4015
4016 // calculate all floating sizes
4017 ImplCalcFloatSizes();
4018
4019 if ( !mnLastResizeDY )
4020 mnLastResizeDY = mnDY;
4021
4022 // is vertical resizing needed
4023 if ( (mnLastResizeDY != rSize.Height()) && (mnDY != rSize.Height()) )
4024 {
4025 nCalcLines = ImplCalcLines( rSize.Height() );
4026 if ( nCalcLines < 1 )
4027 nCalcLines = 1;
4028 rSize = ImplCalcFloatSize( nCalcLines );
4029 }
4030 else
4031 {
4032 nCalcLines = 1;
4033 nTemp = nCalcLines;
4034 Size aTempSize = ImplCalcFloatSize( nTemp );
4035 while ( (aTempSize.Width() > rSize.Width()) &&
4036 (nCalcLines <= maFloatSizes[0].mnLines) )
4037 {
4038 nCalcLines++;
4039 nTemp = nCalcLines;
4040 aTempSize = ImplCalcFloatSize( nTemp );
4041 }
4042 rSize = aTempSize;
4043 }
4044
4045 mnLastResizeDY = rSize.Height();
4046}
4047
4048Size ToolBox::GetOptimalSize() const
4049{
4050 // If we have any expandable entries, then force them to their
4051 // optimal sizes, then reset them afterwards
4052 std::map<vcl::Window*, Size> aExpandables;
4053 for (const ImplToolItem & rItem : mpData->m_aItems)
4054 {
4055 if (rItem.mbExpand)
4056 {
4057 vcl::Window *pWindow = rItem.mpWindow;
4058 SAL_INFO_IF(!pWindow, "vcl.layout", "only tabitems with window supported at the moment")do { if (true && (!pWindow)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_INFO, "vcl.layout")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "only tabitems with window supported at the moment"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "4058" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "only tabitems with window supported at the moment"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "only tabitems with window supported at the moment"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "4058" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "only tabitems with window supported at the moment"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "4058" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "only tabitems with window supported at the moment"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "only tabitems with window supported at the moment"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.layout"
), ("/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
":" "4058" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4059 if (!pWindow)
4060 continue;
4061 Size aWinSize(pWindow->GetSizePixel());
4062 aExpandables[pWindow] = aWinSize;
4063 Size aPrefSize(pWindow->get_preferred_size());
4064 aWinSize.setWidth( aPrefSize.Width() );
4065 pWindow->SetSizePixel(aWinSize);
4066 }
4067 }
4068
4069 Size aSize(const_cast<ToolBox *>(this)->ImplCalcSize( mnLines ));
4070
4071 for (auto const& expandable : aExpandables)
4072 {
4073 vcl::Window *pWindow = expandable.first;
4074 Size aWinSize = expandable.second;
4075 pWindow->SetSizePixel(aWinSize);
4076 }
4077
4078 return aSize;
4079}
4080
4081Size ToolBox::CalcWindowSizePixel( ImplToolItems::size_type nCalcLines )
4082{
4083 return ImplCalcSize( nCalcLines );
4084}
4085
4086Size ToolBox::CalcWindowSizePixel( ImplToolItems::size_type nCalcLines, WindowAlign eAlign )
4087{
4088 return ImplCalcSize( nCalcLines,
4089 (eAlign == WindowAlign::Top || eAlign == WindowAlign::Bottom) ? TB_CALCMODE_HORZ1 : TB_CALCMODE_VERT2 );
4090}
4091
4092ToolBox::ImplToolItems::size_type ToolBox::ImplCountLineBreaks() const
4093{
4094 ImplToolItems::size_type nLines = 0;
4095
4096 for (auto const& item : mpData->m_aItems)
4097 {
4098 if( item.meType == ToolBoxItemType::BREAK )
4099 ++nLines;
4100 }
4101 return nLines;
4102}
4103
4104Size ToolBox::CalcPopupWindowSizePixel()
4105{
4106 // count number of breaks and calc corresponding floating window size
4107 ImplToolItems::size_type nLines = ImplCountLineBreaks();
4108
4109 if( nLines )
4110 ++nLines; // add the first line
4111 else
4112 {
4113 // no breaks found: use quadratic layout
4114 nLines = static_cast<ImplToolItems::size_type>(ceil( sqrt( static_cast<double>(GetItemCount()) ) ));
4115 }
4116
4117 bool bPopup = mpData->mbAssumePopupMode;
4118 mpData->mbAssumePopupMode = true;
4119
4120 Size aSize = CalcFloatingWindowSizePixel( nLines );
4121
4122 mpData->mbAssumePopupMode = bPopup;
4123 return aSize;
4124}
4125
4126Size ToolBox::CalcFloatingWindowSizePixel()
4127{
4128 ImplToolItems::size_type nLines = ImplCountLineBreaks();
4129 ++nLines; // add the first line
4130 return CalcFloatingWindowSizePixel( nLines );
4131}
4132
4133Size ToolBox::CalcFloatingWindowSizePixel( ImplToolItems::size_type nCalcLines )
4134{
4135 bool bFloat = mpData->mbAssumeFloating;
4136 bool bDocking = mpData->mbAssumeDocked;
4137
4138 // simulate floating mode and force reformat before calculating
4139 mpData->mbAssumeFloating = true;
4140 mpData->mbAssumeDocked = false;
4141
4142 Size aSize = ImplCalcFloatSize( nCalcLines );
4143
4144 mbFormat = true;
4145 mpData->mbAssumeFloating = bFloat;
4146 mpData->mbAssumeDocked = bDocking;
4147
4148 return aSize;
4149}
4150
4151Size ToolBox::CalcMinimumWindowSizePixel()
4152{
4153 if( ImplIsFloatingMode() )
4154 return ImplCalcSize( mnFloatLines );
4155 else
4156 {
4157 // create dummy toolbox for measurements
4158 VclPtrInstance< ToolBox > pToolBox( GetParent(), GetStyle() );
4159
4160 // copy until first useful item
4161 for (auto const& item : mpData->m_aItems)
4162 {
4163 pToolBox->CopyItem( *this, item.mnId );
4164 if( (item.meType == ToolBoxItemType::BUTTON) &&
4165 item.mbVisible && !ImplIsFixedControl( &item ) )
4166 break;
4167 }
4168
4169 // add to docking manager if required to obtain a drag area
4170 // (which is accounted for in calcwindowsizepixel)
4171 if( ImplGetDockingManager()->GetDockingWindowWrapper( this ) )
4172 ImplGetDockingManager()->AddWindow( pToolBox );
4173
4174 // account for menu
4175 if( IsMenuEnabled() )
4176 pToolBox->SetMenuType( GetMenuType() );
4177
4178 pToolBox->SetAlign( GetAlign() );
4179 Size aSize = pToolBox->CalcWindowSizePixel( 1 );
4180
4181 ImplGetDockingManager()->RemoveWindow( pToolBox );
4182 pToolBox->Clear();
4183
4184 pToolBox.disposeAndClear();
4185
4186 return aSize;
4187 }
4188}
4189
4190void ToolBox::EnableCustomize( bool bEnable )
4191{
4192 mbCustomize = bEnable;
4193}
4194
4195void ToolBox::LoseFocus()
4196{
4197 ImplChangeHighlight( nullptr, true );
4198
4199 DockingWindow::LoseFocus();
4200}
4201
4202// performs the action associated with an item, ie simulates clicking the item
4203void ToolBox::TriggerItem( sal_uInt16 nItemId )
4204{
4205 mnHighItemId = nItemId;
4206 vcl::KeyCode aKeyCode( 0, 0 );
4207 ImplActivateItem( aKeyCode );
4208}
4209
4210// calls the button's action handler
4211// returns true if action was called
4212bool ToolBox::ImplActivateItem( vcl::KeyCode aKeyCode )
4213{
4214 bool bRet = true;
4215 if( mnHighItemId )
4216 {
4217 ImplToolItem *pToolItem = ImplGetItem( mnHighItemId );
4218
4219 // #107712#, activate can also be called for disabled entries
4220 if( pToolItem && !pToolItem->mbEnabled )
4221 return true;
4222
4223 if( pToolItem && pToolItem->mpWindow && HasFocus() )
4224 {
4225 ImplHideFocus();
4226 mbChangingHighlight = true; // avoid focus change due to loss of focus
4227 pToolItem->mpWindow->ImplControlFocus( GetFocusFlags::Tab );
4228 mbChangingHighlight = false;
4229 }
4230 else
4231 {
4232 mnDownItemId = mnCurItemId = mnHighItemId;
4233 if (pToolItem && (pToolItem->mnBits & ToolBoxItemBits::AUTOCHECK))
4234 {
4235 if ( pToolItem->mnBits & ToolBoxItemBits::RADIOCHECK )
4236 {
4237 if ( pToolItem->meState != TRISTATE_TRUE )
4238 SetItemState( pToolItem->mnId, TRISTATE_TRUE );
4239 }
4240 else
4241 {
4242 if ( pToolItem->meState != TRISTATE_TRUE )
4243 pToolItem->meState = TRISTATE_TRUE;
4244 else
4245 pToolItem->meState = TRISTATE_FALSE;
4246 }
4247 }
4248 mnMouseModifier = aKeyCode.GetModifier();
4249 mbIsKeyEvent = true;
4250 Activate();
4251 Click();
4252
4253 // #107776# we might be destroyed in the selecthandler
4254 VclPtr<vcl::Window> xWindow = this;
4255 Select();
4256 if ( xWindow->IsDisposed() )
4257 return bRet;
4258
4259 Deactivate();
4260 mbIsKeyEvent = false;
4261 mnMouseModifier = 0;
4262 }
4263 }
4264 else
4265 bRet = false;
4266 return bRet;
4267}
4268
4269static bool ImplCloseLastPopup( vcl::Window const *pParent )
4270{
4271 // close last popup toolbox (see also:
4272 // ImplHandleMouseFloatMode(...) in winproc.cxx )
4273
4274 if (ImplGetSVData()->mpWinData->mpFirstFloat)
4275 {
4276 FloatingWindow* pLastLevelFloat = ImplGetSVData()->mpWinData->mpFirstFloat->ImplFindLastLevelFloat();
4277 // only close the floater if it is not our direct parent, which would kill ourself
4278 if( pLastLevelFloat && pLastLevelFloat != pParent )
4279 {
4280 pLastLevelFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
4281 return true;
4282 }
4283 }
4284 return false;
4285}
4286
4287// opens a drop down toolbox item
4288// returns true if item was opened
4289bool ToolBox::ImplOpenItem( vcl::KeyCode aKeyCode )
4290{
4291 sal_uInt16 nCode = aKeyCode.GetCode();
4292 bool bRet = true;
4293
4294 // arrow keys should work only in the opposite direction of alignment (to not break cursor travelling)
4295 if ( ((nCode == KEY_LEFT || nCode == KEY_RIGHT) && IsHorizontal())
4296 || ((nCode == KEY_UP || nCode == KEY_DOWN) && !IsHorizontal()) )
4297 return false;
4298
4299 if( mpData->mbMenubuttonSelected )
4300 {
4301 if( ImplCloseLastPopup( GetParent() ) )
4302 return bRet;
4303 mbIsKeyEvent = true;
4304 if ( maMenuButtonHdl.IsSet() )
4305 maMenuButtonHdl.Call( this );
4306 else
4307 ExecuteCustomMenu( mpData->maMenubuttonItem.maRect );
4308 mpData->mbMenubuttonWasLastSelected = true;
4309 mbIsKeyEvent = false;
4310 }
4311 else if( mnHighItemId && ImplGetItem( mnHighItemId ) &&
4312 (ImplGetItem( mnHighItemId )->mnBits & ToolBoxItemBits::DROPDOWN) )
4313 {
4314 mnDownItemId = mnCurItemId = mnHighItemId;
4315 mnCurPos = GetItemPos( mnCurItemId );
4316 mnLastFocusItemId = mnCurItemId; // save item id for possible later focus restore
4317 mnMouseModifier = aKeyCode.GetModifier();
4318 mbIsKeyEvent = true;
4319 Activate();
4320
4321 mpData->mbDropDownByKeyboard = true;
4322 mpData->maDropdownClickHdl.Call( this );
4323
4324 mbIsKeyEvent = false;
4325 mnMouseModifier = 0;
4326 }
4327 else
4328 bRet = false;
4329
4330 return bRet;
4331}
4332
4333void ToolBox::KeyInput( const KeyEvent& rKEvt )
4334{
4335 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
4336 sal_uInt16 nCode = aKeyCode.GetCode();
4337
4338 vcl::Window *pParent = ImplGetParent();
4339 bool bOldSchoolContainer = ((pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL);
4340 bool bParentIsContainer = bOldSchoolContainer || isContainerWindow(pParent);
4341
4342 bool bForwardKey = false;
4343 bool bGrabFocusToDocument = false;
4344
4345 // #107776# we might be destroyed in the keyhandler
4346 VclPtr<vcl::Window> xWindow = this;
4347
4348 switch ( nCode )
4349 {
4350 case KEY_UP:
4351 {
4352 // Ctrl-Cursor activates next toolbox, indicated by a blue arrow pointing to the left/up
4353 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
4354 break;
4355 if( !IsHorizontal() )
4356 ImplChangeHighlightUpDn( true );
4357 else
4358 ImplOpenItem( aKeyCode );
4359 }
4360 break;
4361 case KEY_LEFT:
4362 {
4363 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
4364 break;
4365 if( IsHorizontal() )
4366 ImplChangeHighlightUpDn( true );
4367 else
4368 ImplOpenItem( aKeyCode );
4369 }
4370 break;
4371 case KEY_DOWN:
4372 {
4373 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
4374 break;
4375 if( !IsHorizontal() )
4376 ImplChangeHighlightUpDn( false );
4377 else
4378 ImplOpenItem( aKeyCode );
4379 }
4380 break;
4381 case KEY_RIGHT:
4382 {
4383 if( aKeyCode.GetModifier() ) // allow only pure cursor keys
4384 break;
4385 if( IsHorizontal() )
4386 ImplChangeHighlightUpDn( false );
4387 else
4388 ImplOpenItem( aKeyCode );
4389 }
4390 break;
4391 case KEY_PAGEUP:
4392 if ( mnCurLine > 1 )
4393 {
4394 if( mnCurLine > mnVisLines )
4395 mnCurLine = mnCurLine - mnVisLines;
4396 else
4397 mnCurLine = 1;
4398 mbFormat = true;
4399 ImplFormat();
4400 InvalidateSpin();
4401 ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
4402 }
4403 break;
4404 case KEY_PAGEDOWN:
4405 if ( mnCurLine+mnVisLines-1 < mnCurLines )
4406 {
4407 if( mnCurLine + 2*mnVisLines-1 < mnCurLines )
4408 mnCurLine = mnCurLine + mnVisLines;
4409 else
4410 mnCurLine = mnCurLines;
4411 mbFormat = true;
4412 ImplFormat();
4413 InvalidateSpin();
4414 ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) );
4415 }
4416 break;
4417 case KEY_END:
4418 {
4419 ImplChangeHighlight( nullptr );
4420 ImplChangeHighlightUpDn( false );
4421 }
4422 break;
4423 case KEY_HOME:
4424 {
4425 ImplChangeHighlight( nullptr );
4426 ImplChangeHighlightUpDn( true );
4427 }
4428 break;
4429 case KEY_ESCAPE:
4430 {
4431 if( !ImplIsFloatingMode() && bParentIsContainer )
4432 DockingWindow::KeyInput( rKEvt );
4433 else
4434 {
4435 // send focus to document pane
4436 vcl::Window *pWin = this;
4437 while( pWin )
4438 {
4439 if( !pWin->GetParent() )
4440 {
4441 pWin->ImplGetFrameWindow()->GetWindow( GetWindowType::Client )->GrabFocus();
4442 break;
4443 }
4444 pWin = pWin->GetParent();
4445 }
4446 }
4447 }
4448 break;
4449 case KEY_RETURN:
4450 {
4451 // #107712#, disabled entries are selectable now
4452 // leave toolbox and move focus to document
4453 if( mnHighItemId )
4454 {
4455 ImplToolItem *pItem = ImplGetItem(mnHighItemId);
4456 if (!pItem || !pItem->mbEnabled)
4457 {
4458 bGrabFocusToDocument = true;
4459 }
4460 }
4461 if( !bGrabFocusToDocument )
4462 bForwardKey = !ImplActivateItem( aKeyCode );
4463 }
4464 break;
4465 case KEY_SPACE:
4466 {
4467 ImplOpenItem( aKeyCode );
4468 }
4469 break;
4470 default:
4471 {
4472 sal_uInt16 aKeyGroup = aKeyCode.GetGroup();
4473 ImplToolItem *pItem = nullptr;
4474 if( mnHighItemId )
4475 pItem = ImplGetItem( mnHighItemId );
4476 // #i13931# forward alphanum keyinput into embedded control
4477 if( (aKeyGroup == KEYGROUP_NUM || aKeyGroup == KEYGROUP_ALPHA ) && pItem && pItem->mpWindow && pItem->mbEnabled )
4478 {
4479 vcl::Window *pFocusWindow = Application::GetFocusWindow();
4480 ImplHideFocus();
4481 mbChangingHighlight = true; // avoid focus change due to loss of focus
4482 pItem->mpWindow->ImplControlFocus( GetFocusFlags::Tab );
4483 mbChangingHighlight = false;
4484 if( pFocusWindow != Application::GetFocusWindow() )
4485 Application::GetFocusWindow()->KeyInput( rKEvt );
4486 }
4487 else
4488 {
4489 // do nothing to avoid key presses going into the document
4490 // while the toolbox has the focus
4491 // just forward function and special keys and combinations with Alt-key
4492 if( aKeyGroup == KEYGROUP_FKEYS || aKeyGroup == KEYGROUP_MISC || aKeyCode.IsMod2() )
4493 bForwardKey = true;
4494 }
4495 }
4496 }
4497
4498 if ( xWindow->IsDisposed() )
4499 return;
4500
4501 // #107251# move focus away if this toolbox was disabled during keyinput
4502 if (HasFocus() && mpData->mbKeyInputDisabled && bParentIsContainer)
4503 {
4504 vcl::Window *pFocusControl = pParent->ImplGetDlgWindow( 0, GetDlgWindowType::First );
4505 if ( pFocusControl && pFocusControl != this )
4506 pFocusControl->ImplControlFocus( GetFocusFlags::Init );
4507 }
4508
4509 // #107712#, leave toolbox
4510 if( bGrabFocusToDocument )
4511 {
4512 GrabFocusToDocument();
4513 return;
4514 }
4515
4516 if( bForwardKey )
4517 DockingWindow::KeyInput( rKEvt );
4518}
4519
4520// returns the current toolbox line of the item
4521ToolBox::ImplToolItems::size_type ToolBox::ImplGetItemLine( ImplToolItem const * pCurrentItem )
4522{
4523 ImplToolItems::size_type nLine = 1;
4524 for (auto const& item : mpData->m_aItems)
4525 {
4526 if ( item.mbBreak )
4527 ++nLine;
4528 if( &item == pCurrentItem)
4529 break;
4530 }
4531 return nLine;
4532}
4533
4534// returns the first displayable item in the given line
4535ImplToolItem* ToolBox::ImplGetFirstValidItem( ImplToolItems::size_type nLine )
4536{
4537 if( !nLine || nLine > mnCurLines )
4538 return nullptr;
4539
4540 nLine--;
4541
4542 ImplToolItems::iterator it = mpData->m_aItems.begin();
4543 while( it != mpData->m_aItems.end() )
4544 {
4545 // find correct line
4546 if ( it->mbBreak )
4547 nLine--;
4548 if( !nLine )
4549 {
4550 // find first useful item
4551 while( it != mpData->m_aItems.end() && ((it->meType != ToolBoxItemType::BUTTON) ||
4552 /*!it->mbEnabled ||*/ !it->mbVisible || ImplIsFixedControl( &(*it) )) )
4553 {
4554 ++it;
4555 if( it == mpData->m_aItems.end() || it->mbBreak )
4556 return nullptr; // no valid items in this line
4557 }
4558 return &(*it);
4559 }
4560 ++it;
4561 }
4562
4563 return (it == mpData->m_aItems.end()) ? nullptr : &(*it);
4564}
4565
4566ToolBox::ImplToolItems::size_type ToolBox::ImplFindItemPos( const ImplToolItem* pItem, const ImplToolItems& rList )
4567{
4568 if( pItem )
4569 {
4570 for( ImplToolItems::size_type nPos = 0; nPos < rList.size(); ++nPos )
4571 if( &rList[ nPos ] == pItem )
4572 return nPos;
4573 }
4574 return ITEM_NOTFOUND;
4575}
4576
4577void ToolBox::ChangeHighlight( ImplToolItems::size_type nPos )
4578{
4579 if ( nPos < GetItemCount() ) {
4580 ImplGrabFocus( GetFocusFlags::NONE );
4581 ImplChangeHighlight ( ImplGetItem ( GetItemId ( nPos ) ) );
4582 }
4583}
4584
4585void ToolBox::ImplChangeHighlight( ImplToolItem const * pItem, bool bNoGrabFocus )
4586{
4587 // avoid recursion due to focus change
4588 if( mbChangingHighlight )
4589 return;
4590
4591 mbChangingHighlight = true;
4592
4593 ImplToolItem* pOldItem = nullptr;
4594
4595 if ( mnHighItemId )
4596 {
4597 ImplHideFocus();
4598 ImplToolItems::size_type nPos = GetItemPos( mnHighItemId );
4599 pOldItem = ImplGetItem( mnHighItemId );
4600 // #i89962# ImplDrawItem can cause Invalidate/Update
4601 // which will in turn ImplShowFocus again
4602 // set mnHighItemId to 0 already to prevent this hen/egg problem
4603 mnHighItemId = 0;
4604 InvalidateItem(nPos);
4605 CallEventListeners( VclEventId::ToolboxHighlightOff, reinterpret_cast< void* >( nPos ) );
4606 }
4607
4608 if( !bNoGrabFocus && pItem != pOldItem && pOldItem && pOldItem->mpWindow )
4609 {
4610 // move focus into toolbox
4611 GrabFocus();
4612 }
4613
4614 if( pItem )
4615 {
4616 ImplToolItems::size_type aPos = ToolBox::ImplFindItemPos( pItem, mpData->m_aItems );
4617 if( aPos != ITEM_NOTFOUND)
4618 {
4619 // check for line breaks
4620 ImplToolItems::size_type nLine = ImplGetItemLine( pItem );
4621
4622 if( nLine >= mnCurLine + mnVisLines )
4623 {
4624 mnCurLine = nLine - mnVisLines + 1;
4625 mbFormat = true;
4626 }
4627 else if ( nLine < mnCurLine )
4628 {
4629 mnCurLine = nLine;
4630 mbFormat = true;
4631 }
4632
4633 if( mbFormat )
4634 {
4635 ImplFormat();
4636 }
4637
4638 mnHighItemId = pItem->mnId;
4639 InvalidateItem(aPos);
4640
4641 ImplShowFocus();
4642
4643 if( pItem->mpWindow )
4644 pItem->mpWindow->GrabFocus();
4645 if( pItem != pOldItem )
4646 CallEventListeners( VclEventId::ToolboxHighlight );
4647 }
4648 }
4649 else
4650 {
4651 ImplHideFocus();
4652 mnHighItemId = 0;
4653 mnCurPos = ITEM_NOTFOUND;
4654 }
4655
4656 mbChangingHighlight = false;
4657}
4658
4659// check for keyboard accessible items
4660static bool ImplIsValidItem( const ImplToolItem* pItem, bool bNotClipped )
4661{
4662 bool bValid = (pItem && pItem->meType == ToolBoxItemType::BUTTON && pItem->mbVisible && !ImplIsFixedControl( pItem )
4663 && pItem->mbEnabled);
4664 if( bValid && bNotClipped && pItem->IsClipped() )
4665 bValid = false;
4666 return bValid;
4667}
4668
4669bool ToolBox::ImplChangeHighlightUpDn( bool bUp, bool bNoCycle )
4670{
4671 ImplToolItem* pToolItem = ImplGetItem( mnHighItemId );
4672
4673 if( !pToolItem || !mnHighItemId )
4674 {
4675 // menubutton highlighted ?
4676 if( mpData->mbMenubuttonSelected )
4677 {
4678 mpData->mbMenubuttonSelected = false;
4679 if( bUp )
4680 {
4681 // select last valid non-clipped item
4682 ImplToolItem* pItem = nullptr;
4683 auto it = std::find_if(mpData->m_aItems.rbegin(), mpData->m_aItems.rend(),
4684 [](const ImplToolItem& rItem) { return ImplIsValidItem( &rItem, true ); });
4685 if( it != mpData->m_aItems.rend() )
4686 pItem = &(*it);
4687
4688 InvalidateMenuButton();
4689 ImplChangeHighlight( pItem );
4690 }
4691 else
4692 {
4693 // select first valid non-clipped item
4694 ImplToolItems::iterator it = std::find_if(mpData->m_aItems.begin(), mpData->m_aItems.end(),
4695 [](const ImplToolItem& rItem) { return ImplIsValidItem( &rItem, true ); });
4696 if( it != mpData->m_aItems.end() )
4697 {
4698 InvalidateMenuButton();
4699 ImplChangeHighlight( &(*it) );
4700 }
4701 }
4702 return true;
4703 }
4704
4705 if( bUp )
4706 {
4707 // Select first valid item
4708 ImplToolItems::iterator it = std::find_if(mpData->m_aItems.begin(), mpData->m_aItems.end(),
4709 [](const ImplToolItem& rItem) { return ImplIsValidItem( &rItem, false ); });
4710
4711 // select the menu button if a clipped item would be selected
4712 if( (it != mpData->m_aItems.end() && &(*it) == ImplGetFirstClippedItem()) && IsMenuEnabled() )
4713 {
4714 ImplChangeHighlight( nullptr );
4715 mpData->mbMenubuttonSelected = true;
4716 InvalidateMenuButton();
4717 }
4718 else
4719 ImplChangeHighlight( (it != mpData->m_aItems.end()) ? &(*it) : nullptr );
4720 return true;
4721 }
4722 else
4723 {
4724 // Select last valid item
4725
4726 // docked toolbars have the menubutton as last item - if this button is enabled
4727 if( ImplHasClippedItems() && IsMenuEnabled() && !ImplIsFloatingMode() )
4728 {
4729 ImplChangeHighlight( nullptr );
4730 mpData->mbMenubuttonSelected = true;
4731 InvalidateMenuButton();
4732 }
4733 else
4734 {
4735 ImplToolItem* pItem = nullptr;
4736 auto it = std::find_if(mpData->m_aItems.rbegin(), mpData->m_aItems.rend(),
4737 [](const ImplToolItem& rItem) { return ImplIsValidItem( &rItem, false ); });
4738 if( it != mpData->m_aItems.rend() )
4739 pItem = &(*it);
4740
4741 ImplChangeHighlight( pItem );
4742 }
4743 return true;
4744 }
4745 }
4746
4747 assert(pToolItem)(static_cast <bool> (pToolItem) ? void (0) : __assert_fail
("pToolItem", "/home/maarten/src/libreoffice/core/vcl/source/window/toolbox.cxx"
, 4747, __extension__ __PRETTY_FUNCTION__))
;
4748
4749 ImplToolItems::size_type pos = ToolBox::ImplFindItemPos( pToolItem, mpData->m_aItems );
4750 ImplToolItems::size_type nCount = mpData->m_aItems.size();
4751
4752 ImplToolItems::size_type i=0;
4753 do
4754 {
4755 if( bUp )
4756 {
4757 if( !pos-- )
4758 {
4759 if( bNoCycle )
4760 return false;
4761
4762 // highlight the menu button if it is the last item
4763 if( ImplHasClippedItems() && IsMenuEnabled() && !ImplIsFloatingMode() )
4764 {
4765 ImplChangeHighlight( nullptr );
4766 mpData->mbMenubuttonSelected = true;
4767 InvalidateMenuButton();
4768 return true;
4769 }
4770 else
4771 pos = nCount-1;
4772 }
4773 }
4774 else
4775 {
4776 if( ++pos >= nCount )
4777 {
4778 if( bNoCycle )
4779 return false;
4780
4781 // highlight the menu button if it is the last item
4782 if( ImplHasClippedItems() && IsMenuEnabled() && !ImplIsFloatingMode() )
4783 {
4784 ImplChangeHighlight( nullptr );
4785 mpData->mbMenubuttonSelected = true;
4786 InvalidateMenuButton();
4787 return true;
4788 }
4789 else
4790 pos = 0;
4791 }
4792 }
4793
4794 pToolItem = &mpData->m_aItems[pos];
4795
4796 if ( ImplIsValidItem( pToolItem, false ) )
4797 break;
4798
4799 } while( ++i < nCount);
4800
4801 if( pToolItem->IsClipped() && IsMenuEnabled() )
4802 {
4803 // select the menu button if a clipped item would be selected
4804 ImplChangeHighlight( nullptr );
4805 mpData->mbMenubuttonSelected = true;
4806 InvalidateMenuButton();
4807 }
4808 else if( i != nCount )
4809 ImplChangeHighlight( pToolItem );
4810 else
4811 return false;
4812
4813 return true;
4814}
4815
4816void ToolBox::ImplShowFocus()
4817{
4818 if( mnHighItemId && HasFocus() )
4819 {
4820 ImplToolItem* pItem = ImplGetItem( mnHighItemId );
4821 if (pItem && pItem->mpWindow && !pItem->mpWindow->IsDisposed())
4822 {
4823 vcl::Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow.get() : pItem->mpWindow.get();
4824 pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = true;
4825 pWin->Invalidate();
4826 }
4827 }
4828}
4829
4830void ToolBox::ImplHideFocus()
4831{
4832 if( mnHighItemId )
4833 {
4834 mpData->mbMenubuttonWasLastSelected = false;
4835 ImplToolItem* pItem = ImplGetItem( mnHighItemId );
4836 if( pItem && pItem->mpWindow )
4837 {
4838 vcl::Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow.get() : pItem->mpWindow.get();
4839 pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = false;
4840 pWin->Invalidate();
4841 }
4842 }
4843
4844 if ( mpData && mpData->mbMenubuttonSelected )
4845 {
4846 mpData->mbMenubuttonWasLastSelected = true;
4847 // remove highlight from menubutton
4848 mpData->mbMenubuttonSelected = false;
4849 InvalidateMenuButton();
4850 }
4851}
4852
4853void ToolBox::ImplDisableFlatButtons()
4854{
4855#ifdef _WIN32 // Check in the Windows registry if an AT tool wants no flat toolboxes
4856 static bool bInit = false, bValue = false;
4857 if( ! bInit )
4858 {
4859 bInit = true;
4860 HKEY hkey;
4861
4862 if( ERROR_SUCCESS == RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\LibreOffice\\Accessibility\\AtToolSupport", &hkey) )
4863 {
4864 DWORD dwType = 0;
4865 wchar_t Data[6]; // possible values: "true", "false", "1", "0", DWORD
4866 DWORD cbData = sizeof(Data);
4867
4868 if( ERROR_SUCCESS == RegQueryValueExW(hkey, L"DisableFlatToolboxButtons",
4869 nullptr, &dwType, reinterpret_cast<LPBYTE>(Data), &cbData) )
4870 {
4871 switch (dwType)
4872 {
4873 case REG_SZ:
4874 bValue = ((0 == wcsicmp(Data, L"1")) || (0 == wcsicmp(Data, L"true")));
4875 break;
4876 case REG_DWORD:
4877 bValue = static_cast<bool>(reinterpret_cast<DWORD *>(Data)[0]);
4878 break;
4879 }
4880 }
4881 RegCloseKey(hkey);
4882 }
4883 }
4884 if( bValue )
4885 mnOutStyle &= ~TOOLBOX_STYLE_FLAT;
4886#else
4887 (void) this; // loplugin:staticmethods
4888#endif
4889}
4890
4891void ToolBox::SetToolbarLayoutMode( ToolBoxLayoutMode eLayout )
4892{
4893 if ( meLayoutMode != eLayout )
4894 meLayoutMode = eLayout;
4895}
4896
4897void ToolBox::SetToolBoxTextPosition( ToolBoxTextPosition ePosition )
4898{
4899 meTextPosition = ePosition;
4900}
4901
4902/* vim:set shiftwidth=4 softtabstop=4 expandtab: */