1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/headbar.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <tools/debug.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/help.hxx>
26 #include <vcl/image.hxx>
27 #include <vcl/salnativewidgets.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/commandevent.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/ptrstyle.hxx>
33 #include <com/sun/star/accessibility/XAccessible.hpp>
39 HeaderBarItemBits mnBits
;
48 #define HEAD_ARROWSIZE1 4
49 #define HEAD_ARROWSIZE2 7
51 #define HEADERBAR_TEXTOFF 2
52 #define HEADERBAR_ARROWOFF 5
53 #define HEADERBAR_SPLITOFF 3
55 #define HEADERBAR_DRAGOUTOFF 15
57 #define HEAD_HITTEST_ITEM (sal_uInt16(0x0001))
58 #define HEAD_HITTEST_DIVIDER (sal_uInt16(0x0002))
60 void HeaderBar::ImplInit( WinBits nWinStyle
)
72 mnItemDragPos
= HEADERBAR_ITEM_NOTFOUND
;
79 if ( nWinStyle
& WB_DRAG
)
83 if ( nWinStyle
& WB_BUTTONSTYLE
)
86 mbButtonStyle
= false;
87 if ( nWinStyle
& WB_BORDER
)
94 if ( nWinStyle
& WB_BOTTOMBORDER
)
98 ImplInitSettings( true, true, true );
101 HeaderBar::HeaderBar(vcl::Window
* pParent
, WinBits nWinStyle
)
102 : Window(pParent
, nWinStyle
& WB_3DLOOK
)
104 SetType(WindowType::HEADERBAR
);
106 SetSizePixel( CalcWindowSizePixel() );
109 Size
HeaderBar::GetOptimalSize() const
111 return CalcWindowSizePixel();
114 HeaderBar::~HeaderBar() = default;
116 void HeaderBar::ApplySettings(vcl::RenderContext
& rRenderContext
)
118 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
120 ApplyControlFont(rRenderContext
, rStyleSettings
.GetToolFont());
122 ApplyControlForeground(rRenderContext
, rStyleSettings
.GetButtonTextColor());
125 ApplyControlBackground(rRenderContext
, rStyleSettings
.GetFaceColor());
128 void HeaderBar::ImplInitSettings(bool bFont
, bool bForeground
, bool bBackground
)
130 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
133 ApplyControlFont(*this, rStyleSettings
.GetToolFont());
135 if (bForeground
|| bFont
)
137 ApplyControlForeground(*this, rStyleSettings
.GetButtonTextColor());
142 ApplyControlBackground(*this, rStyleSettings
.GetFaceColor());
145 tools::Long
HeaderBar::ImplGetItemPos( sal_uInt16 nPos
) const
147 tools::Long nX
= -mnOffset
;
148 for ( size_t i
= 0; i
< nPos
; i
++ )
149 nX
+= mvItemList
[ i
]->mnSize
;
153 tools::Rectangle
HeaderBar::ImplGetItemRect( sal_uInt16 nPos
) const
155 tools::Rectangle
aRect( ImplGetItemPos( nPos
), 0, 0, mnDY
-1 );
156 aRect
.SetRight( aRect
.Left() + mvItemList
[ nPos
]->mnSize
- 1 );
157 // check for overflow on various systems
158 if ( aRect
.Right() > 16000 )
159 aRect
.SetRight( 16000 );
163 sal_uInt16
HeaderBar::ImplHitTest( const Point
& rPos
,
164 tools::Long
& nMouseOff
, sal_uInt16
& nPos
) const
166 size_t nCount
= static_cast<sal_uInt16
>(mvItemList
.size());
167 bool bLastFixed
= true;
168 tools::Long nX
= -mnOffset
;
170 for ( size_t i
= 0; i
< nCount
; i
++ )
172 auto& pItem
= mvItemList
[ i
];
174 if ( rPos
.X() < (nX
+pItem
->mnSize
) )
178 if ( !bLastFixed
&& (rPos
.X() < (nX
+HEADERBAR_SPLITOFF
)) )
180 nMode
= HEAD_HITTEST_DIVIDER
;
182 nMouseOff
= rPos
.X()-nX
+1;
188 if ( rPos
.X() >= (nX
+pItem
->mnSize
-HEADERBAR_SPLITOFF
) )
190 nMode
= HEAD_HITTEST_DIVIDER
;
191 nMouseOff
= rPos
.X()-(nX
+pItem
->mnSize
);
195 nMode
= HEAD_HITTEST_ITEM
;
196 nMouseOff
= rPos
.X()-nX
;
210 auto& pItem
= mvItemList
[ nCount
-1 ];
211 if ( (pItem
->mnSize
< 4) && (rPos
.X() < (nX
+HEADERBAR_SPLITOFF
)) )
214 nMouseOff
= rPos
.X()-nX
+1;
215 return HEAD_HITTEST_DIVIDER
;
222 void HeaderBar::ImplInvertDrag( sal_uInt16 nStartPos
, sal_uInt16 nEndPos
)
224 tools::Rectangle aRect1
= ImplGetItemRect( nStartPos
);
225 tools::Rectangle aRect2
= ImplGetItemRect( nEndPos
);
226 Point aStartPos
= aRect1
.Center();
227 Point aEndPos
= aStartPos
;
228 tools::Rectangle
aStartRect( aStartPos
.X()-2, aStartPos
.Y()-2,
229 aStartPos
.X()+2, aStartPos
.Y()+2 );
231 if ( nEndPos
> nStartPos
)
233 aStartPos
.AdjustX(3 );
234 aEndPos
.setX( aRect2
.Right()-6 );
238 aStartPos
.AdjustX( -3 );
239 aEndPos
.setX( aRect2
.Left()+6 );
242 SetRasterOp( RasterOp::Invert
);
243 DrawRect( aStartRect
);
244 DrawLine( aStartPos
, aEndPos
);
245 if ( nEndPos
> nStartPos
)
247 DrawLine( Point( aEndPos
.X()+1, aEndPos
.Y()-3 ),
248 Point( aEndPos
.X()+1, aEndPos
.Y()+3 ) );
249 DrawLine( Point( aEndPos
.X()+2, aEndPos
.Y()-2 ),
250 Point( aEndPos
.X()+2, aEndPos
.Y()+2 ) );
251 DrawLine( Point( aEndPos
.X()+3, aEndPos
.Y()-1 ),
252 Point( aEndPos
.X()+3, aEndPos
.Y()+1 ) );
253 DrawPixel( Point( aEndPos
.X()+4, aEndPos
.Y() ) );
257 DrawLine( Point( aEndPos
.X()-1, aEndPos
.Y()-3 ),
258 Point( aEndPos
.X()-1, aEndPos
.Y()+3 ) );
259 DrawLine( Point( aEndPos
.X()-2, aEndPos
.Y()-2 ),
260 Point( aEndPos
.X()-2, aEndPos
.Y()+2 ) );
261 DrawLine( Point( aEndPos
.X()-3, aEndPos
.Y()-1 ),
262 Point( aEndPos
.X()-3, aEndPos
.Y()+1 ) );
263 DrawPixel( Point( aEndPos
.X()-4, aEndPos
.Y() ) );
265 SetRasterOp( RasterOp::OverPaint
);
268 void HeaderBar::ImplDrawItem(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPos
, bool bHigh
,
269 const tools::Rectangle
& rItemRect
, const tools::Rectangle
* pRect
)
271 ImplControlValue
aControlValue(0);
272 tools::Rectangle aCtrlRegion
;
273 ControlState
nState(ControlState::NONE
);
275 tools::Rectangle aRect
= rItemRect
;
277 // do not display if there is no space
278 if (aRect
.GetWidth() <= 1)
281 // check of rectangle is visible
284 if (aRect
.Right() < pRect
->Left())
286 else if (aRect
.Left() > pRect
->Right())
291 if (aRect
.Right() < 0)
293 else if (aRect
.Left() > mnDX
)
297 auto& pItem
= mvItemList
[nPos
];
298 HeaderBarItemBits nBits
= pItem
->mnBits
;
299 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
301 if (rRenderContext
.IsNativeControlSupported(ControlType::WindowBackground
, ControlPart::Entire
))
304 rRenderContext
.DrawNativeControl(ControlType::WindowBackground
, ControlPart::Entire
,
305 aCtrlRegion
, nState
, aControlValue
, OUString());
310 // do not draw border
311 aRect
.AdjustTop(mnBorderOff1
);
312 aRect
.AdjustBottom( -mnBorderOff2
);
317 rRenderContext
.DrawWallpaper(aRect
, rRenderContext
.GetBackground());
321 Color
aSelectionTextColor(COL_TRANSPARENT
);
323 if (rRenderContext
.IsNativeControlSupported(ControlType::ListHeader
, ControlPart::Button
))
326 aControlValue
.setTristateVal(ButtonValue::On
);
327 nState
|= ControlState::ENABLED
;
329 nState
|= ControlState::PRESSED
;
330 rRenderContext
.DrawNativeControl(ControlType::ListHeader
, ControlPart::Button
,
331 aCtrlRegion
, nState
, aControlValue
, OUString());
335 // draw separation line
336 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
337 rRenderContext
.DrawLine(Point(aRect
.Right(), aRect
.Top()), Point(aRect
.Right(), aRect
.Bottom()));
342 vcl::RenderTools::DrawSelectionBackground(rRenderContext
, *this, aRect
, 1, true, false, false, &aSelectionTextColor
);
343 else if (!mbButtonStyle
|| (nBits
& HeaderBarItemBits::FLAT
))
344 vcl::RenderTools::DrawSelectionBackground(rRenderContext
, *this, aRect
, 0, true, false, false, &aSelectionTextColor
);
347 // do not draw if there is no space
348 if (aRect
.GetWidth() < 1)
351 // calculate size and position and draw content
352 pItem
->maOutText
= pItem
->maText
;
353 Size aImageSize
= pItem
->maImage
.GetSizePixel();
354 Size
aTxtSize(rRenderContext
.GetTextWidth(pItem
->maOutText
), 0);
355 if (!pItem
->maOutText
.isEmpty())
356 aTxtSize
.setHeight( rRenderContext
.GetTextHeight() );
357 tools::Long nArrowWidth
= 0;
358 if (nBits
& (HeaderBarItemBits::UPARROW
| HeaderBarItemBits::DOWNARROW
))
359 nArrowWidth
= HEAD_ARROWSIZE2
+ HEADERBAR_ARROWOFF
;
361 // do not draw if there is not enough space for the image
362 tools::Long nTestHeight
= aImageSize
.Height();
363 if (!(nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
)))
364 nTestHeight
+= aTxtSize
.Height();
365 if ((aImageSize
.Width() > aRect
.GetWidth()) || (nTestHeight
> aRect
.GetHeight()))
367 aImageSize
.setWidth( 0 );
368 aImageSize
.setHeight( 0 );
371 // cut text to correct length
372 bool bLeftText
= false;
373 tools::Long nMaxTxtWidth
= aRect
.GetWidth() - (HEADERBAR_TEXTOFF
* 2) - nArrowWidth
;
374 if (nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
))
375 nMaxTxtWidth
-= aImageSize
.Width();
376 tools::Long nTxtWidth
= aTxtSize
.Width();
377 if (nTxtWidth
> nMaxTxtWidth
)
380 OUStringBuffer
aBuf(pItem
->maOutText
);
384 aBuf
.remove(aBuf
.getLength() - 3 - 1, 1);
385 nTxtWidth
= rRenderContext
.GetTextWidth(aBuf
.toString());
387 while ((nTxtWidth
> nMaxTxtWidth
) && (aBuf
.getLength() > 3));
388 pItem
->maOutText
= aBuf
.makeStringAndClear();
389 if (pItem
->maOutText
.getLength() == 3)
392 pItem
->maOutText
.clear();
396 // calculate text/imageposition
398 if (!bLeftText
&& (nBits
& HeaderBarItemBits::RIGHT
))
400 nTxtPos
= aRect
.Right() - nTxtWidth
- HEADERBAR_TEXTOFF
;
401 if (nBits
& HeaderBarItemBits::RIGHTIMAGE
)
402 nTxtPos
-= aImageSize
.Width();
404 else if (!bLeftText
&& (nBits
& HeaderBarItemBits::CENTER
))
406 tools::Long nTempWidth
= nTxtWidth
;
407 if (nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
))
408 nTempWidth
+= aImageSize
.Width();
409 nTxtPos
= aRect
.Left() + (aRect
.GetWidth() - nTempWidth
) / 2;
410 if (nBits
& HeaderBarItemBits::LEFTIMAGE
)
411 nTxtPos
+= aImageSize
.Width();
414 if (nTxtPos
+ nTxtWidth
+ nArrowWidth
>= aRect
.Right())
416 nTxtPos
= aRect
.Left() + HEADERBAR_TEXTOFF
;
417 if (nBits
& HeaderBarItemBits::LEFTIMAGE
)
418 nTxtPos
+= aImageSize
.Width();
424 nTxtPos
= aRect
.Left() + HEADERBAR_TEXTOFF
;
425 if (nBits
& HeaderBarItemBits::LEFTIMAGE
)
426 nTxtPos
+= aImageSize
.Width();
427 if (nBits
& HeaderBarItemBits::RIGHT
)
428 nTxtPos
+= nArrowWidth
;
431 // calculate text/imageposition
432 tools::Long nTxtPosY
= 0;
433 if (!pItem
->maOutText
.isEmpty() || (nArrowWidth
&& aTxtSize
.Height()))
435 tools::Long nTempHeight
= aTxtSize
.Height();
436 nTempHeight
+= aImageSize
.Height();
437 nTxtPosY
= aRect
.Top()+((aRect
.GetHeight()-nTempHeight
)/2);
438 if (!(nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
)))
439 nTxtPosY
+= aImageSize
.Height();
443 if (!pItem
->maOutText
.isEmpty())
445 if (aSelectionTextColor
!= COL_TRANSPARENT
)
447 rRenderContext
.Push(PushFlags::TEXTCOLOR
);
448 rRenderContext
.SetTextColor(aSelectionTextColor
);
451 rRenderContext
.DrawText(Point(nTxtPos
, nTxtPosY
), pItem
->maOutText
);
453 rRenderContext
.DrawCtrlText(Point(nTxtPos
, nTxtPosY
), pItem
->maOutText
, 0, pItem
->maOutText
.getLength(), DrawTextFlags::Disable
);
454 if (aSelectionTextColor
!= COL_TRANSPARENT
)
455 rRenderContext
.Pop();
458 // calculate the position and draw image if it is available
459 tools::Long nImagePosY
= 0;
460 if (aImageSize
.Width() && aImageSize
.Height())
462 tools::Long nImagePos
= nTxtPos
;
463 if (nBits
& HeaderBarItemBits::LEFTIMAGE
)
465 nImagePos
-= aImageSize
.Width();
466 if (nBits
& HeaderBarItemBits::RIGHT
)
467 nImagePos
-= nArrowWidth
;
469 else if (nBits
& HeaderBarItemBits::RIGHTIMAGE
)
471 nImagePos
+= nTxtWidth
;
472 if (!(nBits
& HeaderBarItemBits::RIGHT
))
473 nImagePos
+= nArrowWidth
;
477 if (nBits
& HeaderBarItemBits::RIGHT
)
478 nImagePos
= aRect
.Right()-aImageSize
.Width();
479 else if (nBits
& HeaderBarItemBits::CENTER
)
480 nImagePos
= aRect
.Left() + (aRect
.GetWidth() - aImageSize
.Width()) / 2;
482 nImagePos
= aRect
.Left() + HEADERBAR_TEXTOFF
;
485 tools::Long nTempHeight
= aImageSize
.Height();
486 if (!(nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
)))
487 nTempHeight
+= aTxtSize
.Height();
488 nImagePosY
= aRect
.Top() + ((aRect
.GetHeight() - nTempHeight
) / 2);
490 if (nImagePos
+ aImageSize
.Width() <= aRect
.Right())
492 DrawImageFlags nStyle
= DrawImageFlags::NONE
;
494 nStyle
|= DrawImageFlags::Disable
;
495 rRenderContext
.DrawImage(Point(nImagePos
, nImagePosY
), pItem
->maImage
, nStyle
);
499 if (!(nBits
& (HeaderBarItemBits::UPARROW
| HeaderBarItemBits::DOWNARROW
)))
502 tools::Long nArrowX
= nTxtPos
;
503 if (nBits
& HeaderBarItemBits::RIGHT
)
504 nArrowX
-= nArrowWidth
;
506 nArrowX
+= nTxtWidth
+ HEADERBAR_ARROWOFF
;
507 if (!(nBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
)) && pItem
->maText
.isEmpty())
509 if (nBits
& HeaderBarItemBits::RIGHT
)
510 nArrowX
-= aImageSize
.Width();
512 nArrowX
+= aImageSize
.Width();
515 // is there enough space to draw the item?
517 if (nArrowX
< aRect
.Left() + HEADERBAR_TEXTOFF
)
519 else if (nArrowX
+ HEAD_ARROWSIZE2
> aRect
.Right())
525 if (rRenderContext
.IsNativeControlSupported(ControlType::ListHeader
, ControlPart::Arrow
))
527 aCtrlRegion
= tools::Rectangle(Point(nArrowX
, aRect
.Top()), Size(nArrowWidth
, aRect
.GetHeight()));
528 // control value passes 1 if arrow points down, 0 otherwise
529 aControlValue
.setNumericVal((nBits
& HeaderBarItemBits::DOWNARROW
) ? 1 : 0);
530 nState
|= ControlState::ENABLED
;
532 nState
|= ControlState::PRESSED
;
533 rRenderContext
.DrawNativeControl(ControlType::ListHeader
, ControlPart::Arrow
, aCtrlRegion
,
534 nState
, aControlValue
, OUString());
539 if (aTxtSize
.Height())
540 nArrowY
= nTxtPosY
+ (aTxtSize
.Height() / 2);
541 else if (aImageSize
.Width() && aImageSize
.Height())
542 nArrowY
= nImagePosY
+ (aImageSize
.Height() / 2);
544 nArrowY
= aRect
.Top() + ((aRect
.GetHeight() - HEAD_ARROWSIZE2
) / 2);
545 nArrowY
-= HEAD_ARROWSIZE1
- 1;
546 if (nBits
& HeaderBarItemBits::DOWNARROW
)
548 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
549 rRenderContext
.DrawLine(Point(nArrowX
, nArrowY
),
550 Point(nArrowX
+ HEAD_ARROWSIZE2
, nArrowY
));
551 rRenderContext
.DrawLine(Point(nArrowX
, nArrowY
),
552 Point(nArrowX
+ HEAD_ARROWSIZE1
, nArrowY
+ HEAD_ARROWSIZE2
));
553 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
554 rRenderContext
.DrawLine(Point(nArrowX
+ HEAD_ARROWSIZE1
, nArrowY
+ HEAD_ARROWSIZE2
),
555 Point(nArrowX
+ HEAD_ARROWSIZE2
, nArrowY
));
559 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
560 rRenderContext
.DrawLine(Point(nArrowX
, nArrowY
+ HEAD_ARROWSIZE2
),
561 Point(nArrowX
+ HEAD_ARROWSIZE1
, nArrowY
));
562 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
563 rRenderContext
.DrawLine(Point(nArrowX
, nArrowY
+ HEAD_ARROWSIZE2
),
564 Point(nArrowX
+ HEAD_ARROWSIZE2
, nArrowY
+ HEAD_ARROWSIZE2
));
565 rRenderContext
.DrawLine(Point(nArrowX
+ HEAD_ARROWSIZE2
, nArrowY
+ HEAD_ARROWSIZE2
),
566 Point(nArrowX
+ HEAD_ARROWSIZE1
, nArrowY
));
571 void HeaderBar::ImplDrawItem(vcl::RenderContext
& rRenderContext
, sal_uInt16 nPos
,
572 bool bHigh
, const tools::Rectangle
* pRect
)
574 tools::Rectangle aRect
= ImplGetItemRect(nPos
);
575 ImplDrawItem(rRenderContext
, nPos
, bHigh
, aRect
, pRect
);
578 void HeaderBar::ImplUpdate(sal_uInt16 nPos
, bool bEnd
)
580 if (!(IsVisible() && IsUpdateMode()))
583 tools::Rectangle aRect
;
584 size_t nItemCount
= mvItemList
.size();
585 if (nPos
< nItemCount
)
586 aRect
= ImplGetItemRect(nPos
);
589 aRect
.SetBottom( mnDY
- 1 );
591 aRect
.SetLeft( ImplGetItemRect(nItemCount
- 1).Right() );
594 aRect
.SetRight( mnDX
- 1 );
595 aRect
.AdjustTop(mnBorderOff1
);
596 aRect
.AdjustBottom( -mnBorderOff2
);
600 void HeaderBar::ImplStartDrag( const Point
& rMousePos
, bool bCommand
)
603 sal_uInt16 nHitTest
= ImplHitTest( rMousePos
, mnMouseOff
, nPos
);
608 auto& pItem
= mvItemList
[ nPos
];
609 if ( nHitTest
& HEAD_HITTEST_DIVIDER
)
613 if ( ((pItem
->mnBits
& HeaderBarItemBits::CLICKABLE
) && !(pItem
->mnBits
& HeaderBarItemBits::FLAT
)) ||
633 mnCurItemId
= pItem
->mnId
;
643 mnCurItemId
= pItem
->mnId
;
644 mnItemDragPos
= nPos
;
646 mnStartPos
= rMousePos
.X()-mnMouseOff
;
647 mnDragPos
= mnStartPos
;
648 maStartDragHdl
.Call( this );
653 tools::Rectangle
aSizeRect( mnDragPos
, 0, mnDragPos
, mnDragSize
+mnDY
);
654 ShowTracking( aSizeRect
, ShowTrackFlags::Split
);
661 void HeaderBar::ImplDrag( const Point
& rMousePos
)
663 sal_uInt16 nPos
= GetItemPos( mnCurItemId
);
665 mnDragPos
= rMousePos
.X()-mnMouseOff
;
670 tools::Rectangle aItemRect
= ImplGetItemRect( nPos
);
671 bNewOutDrag
= !aItemRect
.IsInside( rMousePos
);
673 // if needed switch on ItemDrag
674 if ( bNewOutDrag
&& mbDragable
&& !mbItemDrag
)
676 if ( (rMousePos
.Y() >= aItemRect
.Top()) && (rMousePos
.Y() <= aItemRect
.Bottom()) )
683 sal_uInt16 nOldItemDragPos
= mnItemDragPos
;
686 bNewOutDrag
= (rMousePos
.Y() < -HEADERBAR_DRAGOUTOFF
) || (rMousePos
.Y() > mnDY
+HEADERBAR_DRAGOUTOFF
);
689 mnItemDragPos
= HEADERBAR_ITEM_NOTFOUND
;
692 sal_uInt16 nTempId
= GetItemId( Point( rMousePos
.X(), 2 ) );
694 mnItemDragPos
= GetItemPos( nTempId
);
697 if ( rMousePos
.X() <= 0 )
700 mnItemDragPos
= GetItemCount()-1;
704 if ( (mnItemDragPos
!= nOldItemDragPos
) &&
705 (nOldItemDragPos
!= nPos
) &&
706 (nOldItemDragPos
!= HEADERBAR_ITEM_NOTFOUND
) )
708 ImplInvertDrag( nPos
, nOldItemDragPos
);
713 if ( bNewOutDrag
!= mbOutDrag
)
718 if ( (mnItemDragPos
!= nOldItemDragPos
) &&
719 (mnItemDragPos
!= nPos
) &&
720 (mnItemDragPos
!= HEADERBAR_ITEM_NOTFOUND
) )
723 ImplInvertDrag( nPos
, mnItemDragPos
);
727 mbOutDrag
= bNewOutDrag
;
731 tools::Rectangle aItemRect
= ImplGetItemRect( nPos
);
732 if ( mnDragPos
< aItemRect
.Left() )
733 mnDragPos
= aItemRect
.Left();
734 if ( (mnDragPos
< 0) || (mnDragPos
> mnDX
-1) )
738 tools::Rectangle
aSizeRect( mnDragPos
, 0, mnDragPos
, mnDragSize
+mnDY
);
739 ShowTracking( aSizeRect
, ShowTrackFlags::Split
);
744 void HeaderBar::ImplEndDrag( bool bCancel
)
748 if ( bCancel
|| mbOutDrag
)
750 if ( mbItemMode
&& (!mbOutDrag
|| mbItemDrag
) )
759 sal_uInt16 nPos
= GetItemPos( mnCurItemId
);
764 SetPointer( PointerStyle::Arrow
);
765 if ( (mnItemDragPos
!= nPos
) &&
766 (mnItemDragPos
!= HEADERBAR_ITEM_NOTFOUND
) )
768 ImplInvertDrag( nPos
, mnItemDragPos
);
769 MoveItem( mnCurItemId
, mnItemDragPos
);
782 tools::Long nDelta
= mnDragPos
- mnStartPos
;
785 auto& pItem
= mvItemList
[ nPos
];
786 pItem
->mnSize
+= nDelta
;
787 ImplUpdate( nPos
, true );
795 mnItemDragPos
= HEADERBAR_ITEM_NOTFOUND
;
801 void HeaderBar::MouseButtonDown( const MouseEvent
& rMEvt
)
803 if ( !rMEvt
.IsLeft() )
806 if ( rMEvt
.GetClicks() == 2 )
810 sal_uInt16 nHitTest
= ImplHitTest( rMEvt
.GetPosPixel(), nTemp
, nPos
);
813 auto& pItem
= mvItemList
[ nPos
];
814 if ( nHitTest
& HEAD_HITTEST_DIVIDER
)
818 mnCurItemId
= pItem
->mnId
;
825 ImplStartDrag( rMEvt
.GetPosPixel(), false );
828 void HeaderBar::MouseMove( const MouseEvent
& rMEvt
)
832 PointerStyle eStyle
= PointerStyle::Arrow
;
833 sal_uInt16 nHitTest
= ImplHitTest( rMEvt
.GetPosPixel(), nTemp1
, nTemp2
);
835 if ( nHitTest
& HEAD_HITTEST_DIVIDER
)
836 eStyle
= PointerStyle::HSizeBar
;
837 SetPointer( eStyle
);
840 void HeaderBar::Tracking( const TrackingEvent
& rTEvt
)
842 Point aMousePos
= rTEvt
.GetMouseEvent().GetPosPixel();
844 if ( rTEvt
.IsTrackingEnded() )
845 ImplEndDrag( rTEvt
.IsTrackingCanceled() );
847 ImplDrag( aMousePos
);
850 void HeaderBar::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
852 if (mnBorderOff1
|| mnBorderOff2
)
854 rRenderContext
.SetLineColor(rRenderContext
.GetSettings().GetStyleSettings().GetDarkShadowColor());
856 rRenderContext
.DrawLine(Point(0, 0), Point(mnDX
- 1, 0));
858 rRenderContext
.DrawLine(Point(0, mnDY
- 1), Point(mnDX
- 1, mnDY
- 1));
859 // #i40393# draw left and right border, if WB_BORDER was set in ImplInit()
860 if (mnBorderOff1
&& mnBorderOff2
)
862 rRenderContext
.DrawLine(Point(0, 0), Point(0, mnDY
- 1));
863 rRenderContext
.DrawLine(Point(mnDX
- 1, 0), Point(mnDX
- 1, mnDY
- 1));
867 sal_uInt16 nCurItemPos
;
869 nCurItemPos
= GetItemPos(mnCurItemId
);
871 nCurItemPos
= HEADERBAR_ITEM_NOTFOUND
;
872 sal_uInt16 nItemCount
= static_cast<sal_uInt16
>(mvItemList
.size());
873 for (sal_uInt16 i
= 0; i
< nItemCount
; i
++)
874 ImplDrawItem(rRenderContext
, i
, (i
== nCurItemPos
), &rRect
);
877 void HeaderBar::Draw( OutputDevice
* pDev
, const Point
& rPos
,
880 Point aPos
= pDev
->LogicToPixel( rPos
);
881 Size aSize
= GetSizePixel();
882 tools::Rectangle
aRect( aPos
, aSize
);
883 vcl::Font aFont
= GetDrawPixelFont( pDev
);
887 pDev
->SetFont( aFont
);
888 if ( nFlags
& DrawFlags::Mono
)
889 pDev
->SetTextColor( COL_BLACK
);
891 pDev
->SetTextColor( GetTextColor() );
892 pDev
->SetTextFillColor();
896 pDev
->DrawWallpaper( aRect
, GetBackground() );
897 if ( mnBorderOff1
|| mnBorderOff2
)
899 pDev
->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() );
901 pDev
->DrawLine( aRect
.TopLeft(), Point( aRect
.Right(), aRect
.Top() ) );
903 pDev
->DrawLine( Point( aRect
.Left(), aRect
.Bottom() ), Point( aRect
.Right(), aRect
.Bottom() ) );
904 // #i40393# draw left and right border, if WB_BORDER was set in ImplInit()
905 if ( mnBorderOff1
&& mnBorderOff2
)
907 pDev
->DrawLine( aRect
.TopLeft(), Point( aRect
.Left(), aRect
.Bottom() ) );
908 pDev
->DrawLine( Point( aRect
.Right(), aRect
.Top() ), Point( aRect
.Right(), aRect
.Bottom() ) );
913 tools::Rectangle
aItemRect( aRect
);
914 size_t nItemCount
= mvItemList
.size();
915 for ( size_t i
= 0; i
< nItemCount
; i
++ )
917 aItemRect
.SetLeft( aRect
.Left()+ImplGetItemPos( i
) );
918 aItemRect
.SetRight( aItemRect
.Left() + mvItemList
[ i
]->mnSize
- 1 );
919 // check for overflow on some systems
920 if ( aItemRect
.Right() > 16000 )
921 aItemRect
.SetRight( 16000 );
922 vcl::Region
aRegion( aRect
);
923 pDev
->SetClipRegion( aRegion
);
924 ImplDrawItem(*pDev
, i
, false, aItemRect
, &aRect
);
925 pDev
->SetClipRegion();
931 void HeaderBar::Resize()
933 Size aSize
= GetOutputSizePixel();
934 if ( IsVisible() && (mnDY
!= aSize
.Height()) )
936 mnDX
= aSize
.Width();
937 mnDY
= aSize
.Height();
940 void HeaderBar::Command( const CommandEvent
& rCEvt
)
942 if ( rCEvt
.IsMouseEvent() && (rCEvt
.GetCommand() == CommandEventId::StartDrag
) && !mbDrag
)
944 ImplStartDrag( rCEvt
.GetMousePosPixel(), true );
948 Window::Command( rCEvt
);
951 void HeaderBar::RequestHelp( const HelpEvent
& rHEvt
)
953 sal_uInt16 nItemId
= GetItemId( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ) );
956 if ( rHEvt
.GetMode() & (HelpEventMode::QUICK
| HelpEventMode::BALLOON
) )
958 tools::Rectangle aItemRect
= GetItemRect( nItemId
);
959 Point aPt
= OutputToScreenPixel( aItemRect
.TopLeft() );
960 aItemRect
.SetLeft( aPt
.X() );
961 aItemRect
.SetTop( aPt
.Y() );
962 aPt
= OutputToScreenPixel( aItemRect
.BottomRight() );
963 aItemRect
.SetRight( aPt
.X() );
964 aItemRect
.SetBottom( aPt
.Y() );
966 OUString aStr
= GetHelpText( nItemId
);
967 if ( aStr
.isEmpty() || !(rHEvt
.GetMode() & HelpEventMode::BALLOON
) )
969 auto& pItem
= mvItemList
[ GetItemPos( nItemId
) ];
970 // Quick-help is only displayed if the text is not fully visible.
971 // Otherwise we display Helptext only if the items do not contain text
972 if ( pItem
->maOutText
!= pItem
->maText
)
973 aStr
= pItem
->maText
;
974 else if (!pItem
->maText
.isEmpty())
980 if ( rHEvt
.GetMode() & HelpEventMode::BALLOON
)
981 Help::ShowBalloon( this, aItemRect
.Center(), aItemRect
, aStr
);
983 Help::ShowQuickHelp( this, aItemRect
, aStr
);
989 Window::RequestHelp( rHEvt
);
992 void HeaderBar::StateChanged( StateChangedType nType
)
994 Window::StateChanged( nType
);
996 if ( nType
== StateChangedType::Enable
)
998 else if ( (nType
== StateChangedType::Zoom
) ||
999 (nType
== StateChangedType::ControlFont
) )
1001 ImplInitSettings( true, false, false );
1004 else if ( nType
== StateChangedType::ControlForeground
)
1006 ImplInitSettings( false, true, false );
1009 else if ( nType
== StateChangedType::ControlBackground
)
1011 ImplInitSettings( false, false, true );
1016 void HeaderBar::DataChanged( const DataChangedEvent
& rDCEvt
)
1018 Window::DataChanged( rDCEvt
);
1020 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1021 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1022 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1023 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1025 ImplInitSettings( true, true, true );
1030 void HeaderBar::EndDrag()
1032 maEndDragHdl
.Call( this );
1035 void HeaderBar::Select()
1037 maSelectHdl
.Call( this );
1040 void HeaderBar::DoubleClick()
1044 void HeaderBar::InsertItem( sal_uInt16 nItemId
, const OUString
& rText
,
1045 tools::Long nSize
, HeaderBarItemBits nBits
, sal_uInt16 nPos
)
1047 DBG_ASSERT( nItemId
, "HeaderBar::InsertItem(): ItemId == 0" );
1048 DBG_ASSERT( GetItemPos( nItemId
) == HEADERBAR_ITEM_NOTFOUND
,
1049 "HeaderBar::InsertItem(): ItemId already exists" );
1051 // create item and insert in the list
1052 std::unique_ptr
<ImplHeadItem
> pItem(new ImplHeadItem
);
1053 pItem
->mnId
= nItemId
;
1054 pItem
->mnBits
= nBits
;
1055 pItem
->mnSize
= nSize
;
1056 pItem
->maText
= rText
;
1057 if ( nPos
< mvItemList
.size() ) {
1058 auto it
= mvItemList
.begin();
1060 mvItemList
.insert( it
, std::move(pItem
) );
1062 mvItemList
.push_back( std::move(pItem
) );
1066 ImplUpdate( nPos
, true );
1069 void HeaderBar::RemoveItem( sal_uInt16 nItemId
)
1071 sal_uInt16 nPos
= GetItemPos( nItemId
);
1072 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1074 if ( nPos
< mvItemList
.size() ) {
1075 auto it
= mvItemList
.begin();
1077 mvItemList
.erase( it
);
1082 void HeaderBar::MoveItem( sal_uInt16 nItemId
, sal_uInt16 nNewPos
)
1084 sal_uInt16 nPos
= GetItemPos( nItemId
);
1085 if ( nPos
== HEADERBAR_ITEM_NOTFOUND
)
1088 if ( nPos
== nNewPos
)
1091 auto it
= mvItemList
.begin();
1093 std::unique_ptr
<ImplHeadItem
> pItem
= std::move(*it
);
1094 mvItemList
.erase( it
);
1095 if ( nNewPos
< nPos
)
1097 it
= mvItemList
.begin();
1099 mvItemList
.insert( it
, std::move(pItem
) );
1100 ImplUpdate( nPos
, true);
1103 void HeaderBar::Clear()
1108 ImplUpdate( 0, true );
1111 void HeaderBar::SetOffset( tools::Long nNewOffset
)
1113 // tdf#129856 (see also #i40393#) invalidate old left and right border area if WB_BORDER was set in ImplInit()
1114 if (mnBorderOff1
&& mnBorderOff2
)
1116 Invalidate(tools::Rectangle(0, 0, 1, mnDY
));
1117 Invalidate(tools::Rectangle(mnDX
- 1, 0, mnDX
, mnDY
));
1121 tools::Rectangle
aRect( 0, mnBorderOff1
, mnDX
-1, mnDY
-mnBorderOff1
-mnBorderOff2
);
1122 tools::Long nDelta
= mnOffset
-nNewOffset
;
1123 mnOffset
= nNewOffset
;
1124 Scroll( nDelta
, 0, aRect
);
1127 sal_uInt16
HeaderBar::GetItemCount() const
1129 return static_cast<sal_uInt16
>(mvItemList
.size());
1132 sal_uInt16
HeaderBar::GetItemPos( sal_uInt16 nItemId
) const
1134 for ( size_t i
= 0, n
= mvItemList
.size(); i
< n
; ++i
) {
1135 auto& pItem
= mvItemList
[ i
];
1136 if ( pItem
->mnId
== nItemId
)
1137 return static_cast<sal_uInt16
>(i
);
1139 return HEADERBAR_ITEM_NOTFOUND
;
1142 sal_uInt16
HeaderBar::GetItemId( sal_uInt16 nPos
) const
1144 ImplHeadItem
* pItem
= (nPos
< mvItemList
.size() ) ? mvItemList
[ nPos
].get() : nullptr;
1151 sal_uInt16
HeaderBar::GetItemId( const Point
& rPos
) const
1153 for ( size_t i
= 0, n
= mvItemList
.size(); i
< n
; ++i
) {
1154 if ( ImplGetItemRect( i
).IsInside( rPos
) ) {
1155 return GetItemId( i
);
1161 tools::Rectangle
HeaderBar::GetItemRect( sal_uInt16 nItemId
) const
1163 tools::Rectangle aRect
;
1164 sal_uInt16 nPos
= GetItemPos( nItemId
);
1165 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1166 aRect
= ImplGetItemRect( nPos
);
1170 void HeaderBar::SetItemSize( sal_uInt16 nItemId
, tools::Long nNewSize
)
1172 sal_uInt16 nPos
= GetItemPos( nItemId
);
1173 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1175 auto& pItem
= mvItemList
[ nPos
];
1176 if ( pItem
->mnSize
!= nNewSize
)
1178 pItem
->mnSize
= nNewSize
;
1179 ImplUpdate( nPos
, true );
1184 tools::Long
HeaderBar::GetItemSize( sal_uInt16 nItemId
) const
1186 sal_uInt16 nPos
= GetItemPos( nItemId
);
1187 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1188 return mvItemList
[ nPos
]->mnSize
;
1193 void HeaderBar::SetItemBits( sal_uInt16 nItemId
, HeaderBarItemBits nNewBits
)
1195 sal_uInt16 nPos
= GetItemPos( nItemId
);
1196 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1198 auto& pItem
= mvItemList
[ nPos
];
1199 if ( pItem
->mnBits
!= nNewBits
)
1201 pItem
->mnBits
= nNewBits
;
1207 HeaderBarItemBits
HeaderBar::GetItemBits( sal_uInt16 nItemId
) const
1209 sal_uInt16 nPos
= GetItemPos( nItemId
);
1210 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1211 return mvItemList
[ nPos
]->mnBits
;
1213 return HeaderBarItemBits::NONE
;
1216 void HeaderBar::SetItemText( sal_uInt16 nItemId
, const OUString
& rText
)
1218 sal_uInt16 nPos
= GetItemPos( nItemId
);
1219 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1221 mvItemList
[ nPos
]->maText
= rText
;
1226 OUString
HeaderBar::GetItemText( sal_uInt16 nItemId
) const
1228 sal_uInt16 nPos
= GetItemPos( nItemId
);
1229 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1230 return mvItemList
[ nPos
]->maText
;
1234 OUString
HeaderBar::GetHelpText( sal_uInt16 nItemId
) const
1236 sal_uInt16 nPos
= GetItemPos( nItemId
);
1237 if ( nPos
!= HEADERBAR_ITEM_NOTFOUND
)
1239 auto& pItem
= mvItemList
[ nPos
];
1240 if ( pItem
->maHelpText
.isEmpty() && !pItem
->maHelpId
.isEmpty() )
1242 Help
* pHelp
= Application::GetHelp();
1244 pItem
->maHelpText
= pHelp
->GetHelpText( OStringToOUString( pItem
->maHelpId
, RTL_TEXTENCODING_UTF8
), this );
1247 return pItem
->maHelpText
;
1253 Size
HeaderBar::CalcWindowSizePixel() const
1255 tools::Long nMaxImageSize
= 0;
1256 Size
aSize( 0, GetTextHeight() );
1258 for (auto& pItem
: mvItemList
)
1260 // take image size into account
1261 tools::Long nImageHeight
= pItem
->maImage
.GetSizePixel().Height();
1262 if ( !(pItem
->mnBits
& (HeaderBarItemBits::LEFTIMAGE
| HeaderBarItemBits::RIGHTIMAGE
)) && !pItem
->maText
.isEmpty() )
1263 nImageHeight
+= aSize
.Height();
1264 if ( nImageHeight
> nMaxImageSize
)
1265 nMaxImageSize
= nImageHeight
;
1268 aSize
.AdjustWidth(pItem
->mnSize
);
1271 if ( nMaxImageSize
> aSize
.Height() )
1272 aSize
.setHeight( nMaxImageSize
);
1275 if ( mbButtonStyle
)
1276 aSize
.AdjustHeight(4 );
1278 aSize
.AdjustHeight(2 );
1279 aSize
.AdjustHeight(mnBorderOff1
+mnBorderOff2
);
1284 css::uno::Reference
< css::accessibility::XAccessible
> HeaderBar::CreateAccessible()
1286 if ( !mxAccessible
.is() )
1288 maCreateAccessibleHdl
.Call( this );
1290 if ( !mxAccessible
.is() )
1291 mxAccessible
= Window::CreateAccessible();
1294 return mxAccessible
;
1297 void HeaderBar::SetAccessible( const css::uno::Reference
< css::accessibility::XAccessible
>& _xAccessible
)
1299 mxAccessible
= _xAccessible
;
1302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */