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/headbar.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <tools/debug.hxx>
23 
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>
32 
33 #include <com/sun/star/accessibility/XAccessible.hpp>
34 
35 class ImplHeadItem
36 {
37 public:
38     sal_uInt16          mnId;
39     HeaderBarItemBits   mnBits;
40     tools::Long                mnSize;
41     OString             maHelpId;
42     Image               maImage;
43     OUString            maOutText;
44     OUString            maText;
45     OUString            maHelpText;
46 };
47 
48 #define HEAD_ARROWSIZE1             4
49 #define HEAD_ARROWSIZE2             7
50 
51 #define HEADERBAR_TEXTOFF           2
52 #define HEADERBAR_ARROWOFF          5
53 #define HEADERBAR_SPLITOFF          3
54 
55 #define HEADERBAR_DRAGOUTOFF        15
56 
57 #define HEAD_HITTEST_ITEM           (sal_uInt16(0x0001))
58 #define HEAD_HITTEST_DIVIDER        (sal_uInt16(0x0002))
59 
ImplInit(WinBits nWinStyle)60 void HeaderBar::ImplInit( WinBits nWinStyle )
61 {
62     mnBorderOff1    = 0;
63     mnBorderOff2    = 0;
64     mnOffset        = 0;
65     mnDX            = 0;
66     mnDY            = 0;
67     mnDragSize      = 0;
68     mnStartPos      = 0;
69     mnDragPos       = 0;
70     mnMouseOff      = 0;
71     mnCurItemId     = 0;
72     mnItemDragPos   = HEADERBAR_ITEM_NOTFOUND;
73     mbDrag          = false;
74     mbItemDrag      = false;
75     mbOutDrag       = false;
76     mbItemMode      = false;
77 
78     // evaluate StyleBits
79     if ( nWinStyle & WB_DRAG )
80         mbDragable = true;
81     else
82         mbDragable = false;
83     if ( nWinStyle & WB_BUTTONSTYLE )
84         mbButtonStyle = true;
85     else
86         mbButtonStyle = false;
87     if ( nWinStyle & WB_BORDER )
88     {
89         mnBorderOff1 = 1;
90         mnBorderOff2 = 1;
91     }
92     else
93     {
94         if ( nWinStyle & WB_BOTTOMBORDER )
95             mnBorderOff2 = 1;
96     }
97 
98     ImplInitSettings( true, true, true );
99 }
100 
HeaderBar(vcl::Window * pParent,WinBits nWinStyle)101 HeaderBar::HeaderBar(vcl::Window* pParent, WinBits nWinStyle)
102     : Window(pParent, nWinStyle & WB_3DLOOK)
103 {
104     SetType(WindowType::HEADERBAR);
105     ImplInit(nWinStyle);
106     SetSizePixel( CalcWindowSizePixel() );
107 }
108 
GetOptimalSize() const109 Size HeaderBar::GetOptimalSize() const
110 {
111     return CalcWindowSizePixel();
112 }
113 
114 HeaderBar::~HeaderBar() = default;
115 
ApplySettings(vcl::RenderContext & rRenderContext)116 void HeaderBar::ApplySettings(vcl::RenderContext& rRenderContext)
117 {
118     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
119 
120     ApplyControlFont(rRenderContext, rStyleSettings.GetToolFont());
121 
122     ApplyControlForeground(rRenderContext, rStyleSettings.GetButtonTextColor());
123     SetTextFillColor();
124 
125     ApplyControlBackground(rRenderContext, rStyleSettings.GetFaceColor());
126 }
127 
ImplInitSettings(bool bFont,bool bForeground,bool bBackground)128 void HeaderBar::ImplInitSettings(bool bFont, bool bForeground, bool bBackground)
129 {
130     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
131 
132     if (bFont)
133         ApplyControlFont(*GetOutDev(), rStyleSettings.GetToolFont());
134 
135     if (bForeground || bFont)
136     {
137         ApplyControlForeground(*GetOutDev(), rStyleSettings.GetButtonTextColor());
138         SetTextFillColor();
139     }
140 
141     if (bBackground)
142         ApplyControlBackground(*GetOutDev(), rStyleSettings.GetFaceColor());
143 }
144 
ImplGetItemPos(sal_uInt16 nPos) const145 tools::Long HeaderBar::ImplGetItemPos( sal_uInt16 nPos ) const
146 {
147     tools::Long nX = -mnOffset;
148     for ( size_t i = 0; i < nPos; i++ )
149         nX += mvItemList[ i ]->mnSize;
150     return nX;
151 }
152 
ImplGetItemRect(sal_uInt16 nPos) const153 tools::Rectangle HeaderBar::ImplGetItemRect( sal_uInt16 nPos ) const
154 {
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 );
160     return aRect;
161 }
162 
ImplDoHitTest(const Point & rPos,tools::Long & nMouseOff,sal_uInt16 & nPos) const163 sal_uInt16 HeaderBar::ImplDoHitTest( const Point& rPos,
164                                tools::Long& nMouseOff, sal_uInt16& nPos ) const
165 {
166     size_t          nCount = static_cast<sal_uInt16>(mvItemList.size());
167     bool            bLastFixed = true;
168     tools::Long            nX = -mnOffset;
169 
170     for ( size_t i = 0; i < nCount; i++ )
171     {
172         auto& pItem = mvItemList[ i ];
173 
174         if ( rPos.X() < (nX+pItem->mnSize) )
175         {
176             sal_uInt16 nMode;
177 
178             if ( !bLastFixed && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) )
179             {
180                 nMode = HEAD_HITTEST_DIVIDER;
181                 nPos = i-1;
182                 nMouseOff = rPos.X()-nX+1;
183             }
184             else
185             {
186                 nPos = i;
187 
188                 if ( rPos.X() >= (nX+pItem->mnSize-HEADERBAR_SPLITOFF) )
189                 {
190                     nMode = HEAD_HITTEST_DIVIDER;
191                     nMouseOff = rPos.X()-(nX+pItem->mnSize);
192                 }
193                 else
194                 {
195                     nMode = HEAD_HITTEST_ITEM;
196                     nMouseOff = rPos.X()-nX;
197                 }
198             }
199 
200             return nMode;
201         }
202 
203         bLastFixed = false;
204 
205         nX += pItem->mnSize;
206     }
207 
208     if ( !bLastFixed )
209     {
210         auto& pItem = mvItemList[ nCount-1 ];
211         if ( (pItem->mnSize < 4)  && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) )
212         {
213             nPos = nCount-1;
214             nMouseOff = rPos.X()-nX+1;
215             return HEAD_HITTEST_DIVIDER;
216         }
217     }
218 
219     return 0;
220 }
221 
ImplInvertDrag(sal_uInt16 nStartPos,sal_uInt16 nEndPos)222 void HeaderBar::ImplInvertDrag( sal_uInt16 nStartPos, sal_uInt16 nEndPos )
223 {
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 );
230 
231     if ( nEndPos > nStartPos )
232     {
233         aStartPos.AdjustX(3 );
234         aEndPos.setX( aRect2.Right()-6 );
235     }
236     else
237     {
238         aStartPos.AdjustX( -3 );
239         aEndPos.setX( aRect2.Left()+6 );
240     }
241 
242     GetOutDev()->SetRasterOp( RasterOp::Invert );
243     GetOutDev()->DrawRect( aStartRect );
244     GetOutDev()->DrawLine( aStartPos, aEndPos );
245     if ( nEndPos > nStartPos )
246     {
247         GetOutDev()->DrawLine( Point( aEndPos.X()+1, aEndPos.Y()-3 ),
248                   Point( aEndPos.X()+1, aEndPos.Y()+3 ) );
249         GetOutDev()->DrawLine( Point( aEndPos.X()+2, aEndPos.Y()-2 ),
250                   Point( aEndPos.X()+2, aEndPos.Y()+2 ) );
251         GetOutDev()->DrawLine( Point( aEndPos.X()+3, aEndPos.Y()-1 ),
252                   Point( aEndPos.X()+3, aEndPos.Y()+1 ) );
253         GetOutDev()->DrawPixel( Point( aEndPos.X()+4, aEndPos.Y() ) );
254     }
255     else
256     {
257         GetOutDev()->DrawLine( Point( aEndPos.X()-1, aEndPos.Y()-3 ),
258                   Point( aEndPos.X()-1, aEndPos.Y()+3 ) );
259         GetOutDev()->DrawLine( Point( aEndPos.X()-2, aEndPos.Y()-2 ),
260                   Point( aEndPos.X()-2, aEndPos.Y()+2 ) );
261         GetOutDev()->DrawLine( Point( aEndPos.X()-3, aEndPos.Y()-1 ),
262                   Point( aEndPos.X()-3, aEndPos.Y()+1 ) );
263         GetOutDev()->DrawPixel( Point( aEndPos.X()-4, aEndPos.Y() ) );
264     }
265     GetOutDev()->SetRasterOp( RasterOp::OverPaint );
266 }
267 
ImplDrawItem(vcl::RenderContext & rRenderContext,sal_uInt16 nPos,bool bHigh,const tools::Rectangle & rItemRect,const tools::Rectangle * pRect)268 void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
269                              const tools::Rectangle& rItemRect, const tools::Rectangle* pRect )
270 {
271     ImplControlValue aControlValue(0);
272     tools::Rectangle aCtrlRegion;
273     ControlState nState(ControlState::NONE);
274 
275     tools::Rectangle aRect = rItemRect;
276 
277     // do not display if there is no space
278     if (aRect.GetWidth() <= 1)
279         return;
280 
281     // check of rectangle is visible
282     if (pRect)
283     {
284         if (aRect.Right() < pRect->Left())
285             return;
286         else if (aRect.Left() > pRect->Right())
287             return;
288     }
289     else
290     {
291         if (aRect.Right() < 0)
292             return;
293         else if (aRect.Left() > mnDX)
294             return;
295     }
296 
297     auto& pItem  = mvItemList[nPos];
298     HeaderBarItemBits nBits = pItem->mnBits;
299     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
300 
301     if (rRenderContext.IsNativeControlSupported(ControlType::WindowBackground, ControlPart::Entire))
302     {
303         aCtrlRegion = aRect;
304         rRenderContext.DrawNativeControl(ControlType::WindowBackground, ControlPart::Entire,
305                                          aCtrlRegion, nState, aControlValue, OUString());
306 
307     }
308     else
309     {
310         // do not draw border
311         aRect.AdjustTop(mnBorderOff1 );
312         aRect.AdjustBottom( -mnBorderOff2 );
313 
314         // delete background
315         if ( !pRect )
316         {
317             rRenderContext.DrawWallpaper(aRect, rRenderContext.GetBackground());
318         }
319     }
320 
321     Color aSelectionTextColor(COL_TRANSPARENT);
322 
323     if (rRenderContext.IsNativeControlSupported(ControlType::ListHeader, ControlPart::Button))
324     {
325         aCtrlRegion = aRect;
326         aControlValue.setTristateVal(ButtonValue::On);
327         nState |= ControlState::ENABLED;
328         if (bHigh)
329             nState |= ControlState::PRESSED;
330         rRenderContext.DrawNativeControl(ControlType::ListHeader, ControlPart::Button,
331                                          aCtrlRegion, nState, aControlValue, OUString());
332     }
333     else
334     {
335         // draw separation line
336         rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
337         rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top()), Point(aRect.Right(), aRect.Bottom()));
338 
339         // draw ButtonStyle
340         // avoid 3D borders
341         if (bHigh)
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);
345     }
346 
347     // do not draw if there is no space
348     if (aRect.GetWidth() < 1)
349         return;
350 
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;
360 
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()))
366     {
367         aImageSize.setWidth( 0 );
368         aImageSize.setHeight( 0 );
369     }
370 
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)
378     {
379         bLeftText = true;
380         OUStringBuffer aBuf(pItem->maOutText);
381         aBuf.append("...");
382         do
383         {
384             aBuf.remove(aBuf.getLength() - 3 - 1, 1);
385             nTxtWidth = rRenderContext.GetTextWidth(aBuf.toString());
386         }
387         while ((nTxtWidth > nMaxTxtWidth) && (aBuf.getLength() > 3));
388         pItem->maOutText = aBuf.makeStringAndClear();
389         if (pItem->maOutText.getLength() == 3)
390         {
391             nTxtWidth = 0;
392             pItem->maOutText.clear();
393         }
394     }
395 
396     // calculate text/imageposition
397     tools::Long nTxtPos;
398     if (!bLeftText && (nBits & HeaderBarItemBits::RIGHT))
399     {
400         nTxtPos = aRect.Right() - nTxtWidth - HEADERBAR_TEXTOFF;
401         if (nBits & HeaderBarItemBits::RIGHTIMAGE)
402             nTxtPos -= aImageSize.Width();
403     }
404     else if (!bLeftText && (nBits & HeaderBarItemBits::CENTER))
405     {
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();
412         if (nArrowWidth)
413         {
414             if (nTxtPos + nTxtWidth + nArrowWidth >= aRect.Right())
415             {
416                 nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF;
417                 if (nBits & HeaderBarItemBits::LEFTIMAGE)
418                     nTxtPos += aImageSize.Width();
419             }
420         }
421     }
422     else
423     {
424         nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF;
425         if (nBits & HeaderBarItemBits::LEFTIMAGE)
426             nTxtPos += aImageSize.Width();
427         if (nBits & HeaderBarItemBits::RIGHT)
428             nTxtPos += nArrowWidth;
429     }
430 
431     // calculate text/imageposition
432     tools::Long nTxtPosY = 0;
433     if (!pItem->maOutText.isEmpty() || (nArrowWidth && aTxtSize.Height()))
434     {
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();
440     }
441 
442     // display text
443     if (!pItem->maOutText.isEmpty())
444     {
445         if (aSelectionTextColor != COL_TRANSPARENT)
446         {
447             rRenderContext.Push(PushFlags::TEXTCOLOR);
448             rRenderContext.SetTextColor(aSelectionTextColor);
449         }
450         if (IsEnabled())
451             rRenderContext.DrawText(Point(nTxtPos, nTxtPosY), pItem->maOutText);
452         else
453             rRenderContext.DrawCtrlText(Point(nTxtPos, nTxtPosY), pItem->maOutText, 0, pItem->maOutText.getLength(), DrawTextFlags::Disable);
454         if (aSelectionTextColor != COL_TRANSPARENT)
455             rRenderContext.Pop();
456     }
457 
458     // calculate the position and draw image if it is available
459     tools::Long nImagePosY = 0;
460     if (aImageSize.Width() && aImageSize.Height())
461     {
462         tools::Long nImagePos = nTxtPos;
463         if (nBits & HeaderBarItemBits::LEFTIMAGE)
464         {
465             nImagePos -= aImageSize.Width();
466             if (nBits & HeaderBarItemBits::RIGHT)
467                 nImagePos -= nArrowWidth;
468         }
469         else if (nBits & HeaderBarItemBits::RIGHTIMAGE)
470         {
471             nImagePos += nTxtWidth;
472             if (!(nBits & HeaderBarItemBits::RIGHT))
473                 nImagePos += nArrowWidth;
474         }
475         else
476         {
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;
481             else
482                 nImagePos = aRect.Left() + HEADERBAR_TEXTOFF;
483         }
484 
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);
489 
490         if (nImagePos + aImageSize.Width() <= aRect.Right())
491         {
492             DrawImageFlags nStyle = DrawImageFlags::NONE;
493             if (!IsEnabled())
494                 nStyle |= DrawImageFlags::Disable;
495             rRenderContext.DrawImage(Point(nImagePos, nImagePosY), pItem->maImage, nStyle);
496         }
497     }
498 
499     if (!(nBits & (HeaderBarItemBits::UPARROW | HeaderBarItemBits::DOWNARROW)))
500         return;
501 
502     tools::Long nArrowX = nTxtPos;
503     if (nBits & HeaderBarItemBits::RIGHT)
504         nArrowX -= nArrowWidth;
505     else
506         nArrowX += nTxtWidth + HEADERBAR_ARROWOFF;
507     if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) && pItem->maText.isEmpty())
508     {
509         if (nBits & HeaderBarItemBits::RIGHT)
510             nArrowX -= aImageSize.Width();
511         else
512             nArrowX += aImageSize.Width();
513     }
514 
515     // is there enough space to draw the item?
516     bool bDraw = true;
517     if (nArrowX < aRect.Left() + HEADERBAR_TEXTOFF)
518         bDraw = false;
519     else if (nArrowX + HEAD_ARROWSIZE2 > aRect.Right())
520         bDraw = false;
521 
522     if (!bDraw)
523         return;
524 
525     if (rRenderContext.IsNativeControlSupported(ControlType::ListHeader, ControlPart::Arrow))
526     {
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;
531         if (bHigh)
532             nState |= ControlState::PRESSED;
533         rRenderContext.DrawNativeControl(ControlType::ListHeader, ControlPart::Arrow, aCtrlRegion,
534                                          nState, aControlValue, OUString());
535     }
536     else
537     {
538         tools::Long nArrowY;
539         if (aTxtSize.Height())
540             nArrowY = nTxtPosY + (aTxtSize.Height() / 2);
541         else if (aImageSize.Width() && aImageSize.Height())
542             nArrowY = nImagePosY + (aImageSize.Height() / 2);
543         else
544             nArrowY = aRect.Top() + ((aRect.GetHeight() - HEAD_ARROWSIZE2) / 2);
545         nArrowY -= HEAD_ARROWSIZE1 - 1;
546         if (nBits & HeaderBarItemBits::DOWNARROW)
547         {
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));
556         }
557         else
558         {
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));
567         }
568     }
569 }
570 
ImplDrawItem(vcl::RenderContext & rRenderContext,sal_uInt16 nPos,bool bHigh,const tools::Rectangle * pRect)571 void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos,
572                              bool bHigh, const tools::Rectangle* pRect )
573 {
574     tools::Rectangle aRect = ImplGetItemRect(nPos);
575     ImplDrawItem(rRenderContext, nPos, bHigh, aRect, pRect );
576 }
577 
ImplUpdate(sal_uInt16 nPos,bool bEnd)578 void HeaderBar::ImplUpdate(sal_uInt16 nPos, bool bEnd)
579 {
580     if (!(IsVisible() && IsUpdateMode()))
581         return;
582 
583     tools::Rectangle aRect;
584     size_t nItemCount = mvItemList.size();
585     if (nPos < nItemCount)
586         aRect = ImplGetItemRect(nPos);
587     else
588     {
589         aRect.SetBottom( mnDY - 1 );
590         if (nItemCount)
591             aRect.SetLeft( ImplGetItemRect(nItemCount - 1).Right() );
592     }
593     if (bEnd)
594         aRect.SetRight( mnDX - 1 );
595     aRect.AdjustTop(mnBorderOff1 );
596     aRect.AdjustBottom( -mnBorderOff2 );
597     Invalidate(aRect);
598 }
599 
ImplStartDrag(const Point & rMousePos,bool bCommand)600 void HeaderBar::ImplStartDrag( const Point& rMousePos, bool bCommand )
601 {
602     sal_uInt16  nPos;
603     sal_uInt16  nHitTest = ImplDoHitTest( rMousePos, mnMouseOff, nPos );
604     if ( !nHitTest )
605         return;
606 
607     mbDrag = false;
608     auto& pItem = mvItemList[ nPos ];
609     if ( nHitTest & HEAD_HITTEST_DIVIDER )
610         mbDrag = true;
611     else
612     {
613         if ( ((pItem->mnBits & HeaderBarItemBits::CLICKABLE) && !(pItem->mnBits & HeaderBarItemBits::FLAT)) ||
614              mbDragable )
615         {
616             mbItemMode = true;
617             mbDrag = true;
618             if ( bCommand )
619             {
620                 if ( mbDragable )
621                     mbItemDrag = true;
622                 else
623                 {
624                     mbItemMode = false;
625                     mbDrag = false;
626                 }
627             }
628         }
629         else
630         {
631             if ( !bCommand )
632             {
633                 mnCurItemId = pItem->mnId;
634                 Select();
635                 mnCurItemId = 0;
636             }
637         }
638     }
639 
640     if ( mbDrag )
641     {
642         mbOutDrag = false;
643         mnCurItemId = pItem->mnId;
644         mnItemDragPos = nPos;
645         StartTracking();
646         mnStartPos = rMousePos.X()-mnMouseOff;
647         mnDragPos = mnStartPos;
648         maStartDragHdl.Call( this );
649         if (mbItemMode)
650             Invalidate();
651         else
652         {
653             tools::Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY );
654             ShowTracking( aSizeRect, ShowTrackFlags::Split );
655         }
656     }
657     else
658         mnMouseOff = 0;
659 }
660 
ImplDrag(const Point & rMousePos)661 void HeaderBar::ImplDrag( const Point& rMousePos )
662 {
663     sal_uInt16  nPos = GetItemPos( mnCurItemId );
664 
665     mnDragPos = rMousePos.X()-mnMouseOff;
666     if ( mbItemMode )
667     {
668         bool bNewOutDrag;
669 
670         tools::Rectangle aItemRect = ImplGetItemRect( nPos );
671         bNewOutDrag = !aItemRect.IsInside( rMousePos );
672 
673         //  if needed switch on ItemDrag
674         if ( bNewOutDrag && mbDragable && !mbItemDrag )
675         {
676             if ( (rMousePos.Y() >= aItemRect.Top()) && (rMousePos.Y() <= aItemRect.Bottom()) )
677             {
678                 mbItemDrag = true;
679                 Invalidate();
680             }
681         }
682 
683         sal_uInt16 nOldItemDragPos = mnItemDragPos;
684         if ( mbItemDrag )
685         {
686             bNewOutDrag = (rMousePos.Y() < -HEADERBAR_DRAGOUTOFF) || (rMousePos.Y() > mnDY+HEADERBAR_DRAGOUTOFF);
687 
688             if ( bNewOutDrag )
689                 mnItemDragPos = HEADERBAR_ITEM_NOTFOUND;
690             else
691             {
692                 sal_uInt16 nTempId = GetItemId( Point( rMousePos.X(), 2 ) );
693                 if ( nTempId )
694                     mnItemDragPos = GetItemPos( nTempId );
695                 else
696                 {
697                     if ( rMousePos.X() <= 0 )
698                         mnItemDragPos = 0;
699                     else
700                         mnItemDragPos = GetItemCount()-1;
701                 }
702             }
703 
704             if ( (mnItemDragPos != nOldItemDragPos) &&
705                  (nOldItemDragPos != nPos) &&
706                  (nOldItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
707             {
708                 ImplInvertDrag( nPos, nOldItemDragPos );
709                 Invalidate();
710             }
711         }
712 
713         if ( bNewOutDrag != mbOutDrag )
714             Invalidate();
715 
716         if ( mbItemDrag  )
717         {
718             if ( (mnItemDragPos != nOldItemDragPos) &&
719                  (mnItemDragPos != nPos) &&
720                  (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
721             {
722                 Invalidate();
723                 ImplInvertDrag( nPos, mnItemDragPos );
724             }
725         }
726 
727         mbOutDrag = bNewOutDrag;
728     }
729     else
730     {
731         tools::Rectangle aItemRect = ImplGetItemRect( nPos );
732         if ( mnDragPos < aItemRect.Left() )
733             mnDragPos = aItemRect.Left();
734         if ( (mnDragPos < 0) || (mnDragPos > mnDX-1) )
735             HideTracking();
736         else
737         {
738             tools::Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY );
739             ShowTracking( aSizeRect, ShowTrackFlags::Split );
740         }
741     }
742 }
743 
ImplEndDrag(bool bCancel)744 void HeaderBar::ImplEndDrag( bool bCancel )
745 {
746     HideTracking();
747 
748     if ( bCancel || mbOutDrag )
749     {
750         if ( mbItemMode && (!mbOutDrag || mbItemDrag) )
751         {
752             Invalidate();
753         }
754 
755         mnCurItemId = 0;
756     }
757     else
758     {
759         sal_uInt16 nPos = GetItemPos( mnCurItemId );
760         if ( mbItemMode )
761         {
762             if ( mbItemDrag )
763             {
764                 SetPointer( PointerStyle::Arrow );
765                 if ( (mnItemDragPos != nPos) &&
766                      (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) )
767                 {
768                     ImplInvertDrag( nPos, mnItemDragPos );
769                     MoveItem( mnCurItemId, mnItemDragPos );
770                 }
771                 else
772                     Invalidate();
773             }
774             else
775             {
776                 Select();
777                 ImplUpdate( nPos );
778             }
779         }
780         else
781         {
782             tools::Long nDelta = mnDragPos - mnStartPos;
783             if ( nDelta )
784             {
785                 auto& pItem = mvItemList[ nPos ];
786                 pItem->mnSize += nDelta;
787                 ImplUpdate( nPos, true );
788             }
789         }
790     }
791 
792     mbDrag          = false;
793     EndDrag();
794     mnCurItemId     = 0;
795     mnItemDragPos   = HEADERBAR_ITEM_NOTFOUND;
796     mbOutDrag       = false;
797     mbItemMode      = false;
798     mbItemDrag      = false;
799 }
800 
MouseButtonDown(const MouseEvent & rMEvt)801 void HeaderBar::MouseButtonDown( const MouseEvent& rMEvt )
802 {
803     if ( !rMEvt.IsLeft() )
804         return;
805 
806     if ( rMEvt.GetClicks() == 2 )
807     {
808         tools::Long    nTemp;
809         sal_uInt16  nPos;
810         sal_uInt16  nHitTest = ImplDoHitTest( rMEvt.GetPosPixel(), nTemp, nPos );
811         if ( nHitTest )
812         {
813             auto& pItem = mvItemList[ nPos ];
814             if ( nHitTest & HEAD_HITTEST_DIVIDER )
815                 mbItemMode = false;
816             else
817                 mbItemMode = true;
818             mnCurItemId = pItem->mnId;
819             DoubleClick();
820             mbItemMode = false;
821             mnCurItemId = 0;
822         }
823     }
824     else
825         ImplStartDrag( rMEvt.GetPosPixel(), false );
826 }
827 
MouseMove(const MouseEvent & rMEvt)828 void HeaderBar::MouseMove( const MouseEvent& rMEvt )
829 {
830     tools::Long            nTemp1;
831     sal_uInt16          nTemp2;
832     PointerStyle    eStyle = PointerStyle::Arrow;
833     sal_uInt16          nHitTest = ImplDoHitTest( rMEvt.GetPosPixel(), nTemp1, nTemp2 );
834 
835     if ( nHitTest & HEAD_HITTEST_DIVIDER )
836         eStyle = PointerStyle::HSizeBar;
837     SetPointer( eStyle );
838 }
839 
Tracking(const TrackingEvent & rTEvt)840 void HeaderBar::Tracking( const TrackingEvent& rTEvt )
841 {
842     Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
843 
844     if ( rTEvt.IsTrackingEnded() )
845         ImplEndDrag( rTEvt.IsTrackingCanceled() );
846     else
847         ImplDrag( aMousePos );
848 }
849 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)850 void HeaderBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
851 {
852     if (mnBorderOff1 || mnBorderOff2)
853     {
854         rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor());
855         if (mnBorderOff1)
856             rRenderContext.DrawLine(Point(0, 0), Point(mnDX - 1, 0));
857         if (mnBorderOff2)
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)
861         {
862             rRenderContext.DrawLine(Point(0, 0), Point(0, mnDY - 1));
863             rRenderContext.DrawLine(Point(mnDX - 1, 0), Point(mnDX - 1, mnDY - 1));
864         }
865     }
866 
867     sal_uInt16 nCurItemPos;
868     if (mbDrag)
869         nCurItemPos = GetItemPos(mnCurItemId);
870     else
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);
875 }
876 
Draw(OutputDevice * pDev,const Point & rPos,DrawFlags nFlags)877 void HeaderBar::Draw( OutputDevice* pDev, const Point& rPos,
878                       DrawFlags nFlags )
879 {
880     Point       aPos  = pDev->LogicToPixel( rPos );
881     Size        aSize = GetSizePixel();
882     tools::Rectangle   aRect( aPos, aSize );
883     vcl::Font   aFont = GetDrawPixelFont( pDev );
884 
885     pDev->Push();
886     pDev->SetMapMode();
887     pDev->SetFont( aFont );
888     if ( nFlags & DrawFlags::Mono )
889         pDev->SetTextColor( COL_BLACK );
890     else
891         pDev->SetTextColor( GetTextColor() );
892     pDev->SetTextFillColor();
893 
894     // draw background
895     {
896         pDev->DrawWallpaper( aRect, GetBackground() );
897         if ( mnBorderOff1 || mnBorderOff2 )
898         {
899             pDev->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() );
900             if ( mnBorderOff1 )
901                 pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right(), aRect.Top() ) );
902             if ( mnBorderOff2 )
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 )
906             {
907                 pDev->DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom() ) );
908                 pDev->DrawLine( Point( aRect.Right(), aRect.Top() ), Point( aRect.Right(), aRect.Bottom() ) );
909             }
910         }
911     }
912 
913     tools::Rectangle aItemRect( aRect );
914     size_t nItemCount = mvItemList.size();
915     for ( size_t i = 0; i < nItemCount; i++ )
916     {
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();
926     }
927 
928     pDev->Pop();
929 }
930 
Resize()931 void HeaderBar::Resize()
932 {
933     Size aSize = GetOutputSizePixel();
934     if ( IsVisible() && (mnDY != aSize.Height()) )
935         Invalidate();
936     mnDX = aSize.Width();
937     mnDY = aSize.Height();
938 }
939 
Command(const CommandEvent & rCEvt)940 void HeaderBar::Command( const CommandEvent& rCEvt )
941 {
942     if ( rCEvt.IsMouseEvent() && (rCEvt.GetCommand() == CommandEventId::StartDrag) && !mbDrag )
943     {
944         ImplStartDrag( rCEvt.GetMousePosPixel(), true );
945         return;
946     }
947 
948     Window::Command( rCEvt );
949 }
950 
RequestHelp(const HelpEvent & rHEvt)951 void HeaderBar::RequestHelp( const HelpEvent& rHEvt )
952 {
953     sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
954     if ( nItemId )
955     {
956         if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
957         {
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() );
965 
966             OUString aStr = GetHelpText( nItemId );
967             if ( aStr.isEmpty() || !(rHEvt.GetMode() & HelpEventMode::BALLOON) )
968             {
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())
975                     aStr.clear();
976             }
977 
978             if (!aStr.isEmpty())
979             {
980                 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
981                     Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
982                 else
983                     Help::ShowQuickHelp( this, aItemRect, aStr );
984                 return;
985             }
986         }
987     }
988 
989     Window::RequestHelp( rHEvt );
990 }
991 
StateChanged(StateChangedType nType)992 void HeaderBar::StateChanged( StateChangedType nType )
993 {
994     Window::StateChanged( nType );
995 
996     if ( nType == StateChangedType::Enable )
997         Invalidate();
998     else if ( (nType == StateChangedType::Zoom) ||
999               (nType == StateChangedType::ControlFont) )
1000     {
1001         ImplInitSettings( true, false, false );
1002         Invalidate();
1003     }
1004     else if ( nType == StateChangedType::ControlForeground )
1005     {
1006         ImplInitSettings( false, true, false );
1007         Invalidate();
1008     }
1009     else if ( nType == StateChangedType::ControlBackground )
1010     {
1011         ImplInitSettings( false, false, true );
1012         Invalidate();
1013     }
1014 }
1015 
DataChanged(const DataChangedEvent & rDCEvt)1016 void HeaderBar::DataChanged( const DataChangedEvent& rDCEvt )
1017 {
1018     Window::DataChanged( rDCEvt );
1019 
1020     if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1021          (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1022          ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1023           (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1024     {
1025         ImplInitSettings( true, true, true );
1026         Invalidate();
1027     }
1028 }
1029 
EndDrag()1030 void HeaderBar::EndDrag()
1031 {
1032     maEndDragHdl.Call( this );
1033 }
1034 
Select()1035 void HeaderBar::Select()
1036 {
1037     maSelectHdl.Call( this );
1038 }
1039 
DoubleClick()1040 void HeaderBar::DoubleClick()
1041 {
1042 }
1043 
InsertItem(sal_uInt16 nItemId,const OUString & rText,tools::Long nSize,HeaderBarItemBits nBits,sal_uInt16 nPos)1044 void HeaderBar::InsertItem( sal_uInt16 nItemId, const OUString& rText,
1045                             tools::Long nSize, HeaderBarItemBits nBits, sal_uInt16 nPos )
1046 {
1047     DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" );
1048     DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND,
1049                 "HeaderBar::InsertItem(): ItemId already exists" );
1050 
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();
1059         it += nPos;
1060         mvItemList.insert( it, std::move(pItem) );
1061     } else {
1062         mvItemList.push_back( std::move(pItem) );
1063     }
1064 
1065     // update display
1066     ImplUpdate( nPos, true );
1067 }
1068 
RemoveItem(sal_uInt16 nItemId)1069 void HeaderBar::RemoveItem( sal_uInt16 nItemId )
1070 {
1071     sal_uInt16 nPos = GetItemPos( nItemId );
1072     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1073     {
1074         if ( nPos < mvItemList.size() ) {
1075             auto it = mvItemList.begin();
1076             it += nPos;
1077             mvItemList.erase( it );
1078         }
1079     }
1080 }
1081 
MoveItem(sal_uInt16 nItemId,sal_uInt16 nNewPos)1082 void HeaderBar::MoveItem( sal_uInt16 nItemId, sal_uInt16 nNewPos )
1083 {
1084     sal_uInt16 nPos = GetItemPos( nItemId );
1085     if ( nPos == HEADERBAR_ITEM_NOTFOUND )
1086         return;
1087 
1088     if ( nPos == nNewPos )
1089         return;
1090 
1091     auto it = mvItemList.begin();
1092     it += nPos;
1093     std::unique_ptr<ImplHeadItem> pItem = std::move(*it);
1094     mvItemList.erase( it );
1095     if ( nNewPos < nPos )
1096         nPos = nNewPos;
1097     it = mvItemList.begin();
1098     it += nNewPos;
1099     mvItemList.insert( it, std::move(pItem) );
1100     ImplUpdate( nPos, true);
1101 }
1102 
Clear()1103 void HeaderBar::Clear()
1104 {
1105     // delete all items
1106     mvItemList.clear();
1107 
1108     ImplUpdate( 0, true );
1109 }
1110 
SetOffset(tools::Long nNewOffset)1111 void HeaderBar::SetOffset( tools::Long nNewOffset )
1112 {
1113     // tdf#129856 (see also #i40393#) invalidate old left and right border area if WB_BORDER was set in ImplInit()
1114     if (mnBorderOff1 && mnBorderOff2)
1115     {
1116         Invalidate(tools::Rectangle(0, 0, 1, mnDY));
1117         Invalidate(tools::Rectangle(mnDX - 1, 0, mnDX, mnDY));
1118     }
1119 
1120     // move area
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 );
1125 }
1126 
GetItemCount() const1127 sal_uInt16 HeaderBar::GetItemCount() const
1128 {
1129     return static_cast<sal_uInt16>(mvItemList.size());
1130 }
1131 
GetItemPos(sal_uInt16 nItemId) const1132 sal_uInt16 HeaderBar::GetItemPos( sal_uInt16 nItemId ) const
1133 {
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);
1138     }
1139     return HEADERBAR_ITEM_NOTFOUND;
1140 }
1141 
GetItemId(sal_uInt16 nPos) const1142 sal_uInt16 HeaderBar::GetItemId( sal_uInt16 nPos ) const
1143 {
1144     ImplHeadItem* pItem = (nPos < mvItemList.size() ) ? mvItemList[ nPos ].get() : nullptr;
1145     if ( pItem )
1146         return pItem->mnId;
1147     else
1148         return 0;
1149 }
1150 
GetItemId(const Point & rPos) const1151 sal_uInt16 HeaderBar::GetItemId( const Point& rPos ) const
1152 {
1153     for ( size_t i = 0, n = mvItemList.size(); i < n; ++i ) {
1154         if ( ImplGetItemRect( i ).IsInside( rPos ) ) {
1155             return GetItemId( i );
1156         }
1157     }
1158     return 0;
1159 }
1160 
GetItemRect(sal_uInt16 nItemId) const1161 tools::Rectangle HeaderBar::GetItemRect( sal_uInt16 nItemId ) const
1162 {
1163     tools::Rectangle aRect;
1164     sal_uInt16 nPos = GetItemPos( nItemId );
1165     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1166         aRect = ImplGetItemRect( nPos );
1167     return aRect;
1168 }
1169 
SetItemSize(sal_uInt16 nItemId,tools::Long nNewSize)1170 void HeaderBar::SetItemSize( sal_uInt16 nItemId, tools::Long nNewSize )
1171 {
1172     sal_uInt16 nPos = GetItemPos( nItemId );
1173     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1174     {
1175         auto& pItem = mvItemList[ nPos ];
1176         if ( pItem->mnSize != nNewSize )
1177         {
1178             pItem->mnSize = nNewSize;
1179             ImplUpdate( nPos, true );
1180         }
1181     }
1182 }
1183 
GetItemSize(sal_uInt16 nItemId) const1184 tools::Long HeaderBar::GetItemSize( sal_uInt16 nItemId ) const
1185 {
1186     sal_uInt16 nPos = GetItemPos( nItemId );
1187     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1188         return mvItemList[ nPos ]->mnSize;
1189     else
1190         return 0;
1191 }
1192 
SetItemBits(sal_uInt16 nItemId,HeaderBarItemBits nNewBits)1193 void HeaderBar::SetItemBits( sal_uInt16 nItemId, HeaderBarItemBits nNewBits )
1194 {
1195     sal_uInt16 nPos = GetItemPos( nItemId );
1196     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1197     {
1198         auto& pItem = mvItemList[ nPos ];
1199         if ( pItem->mnBits != nNewBits )
1200         {
1201             pItem->mnBits = nNewBits;
1202             ImplUpdate( nPos );
1203         }
1204     }
1205 }
1206 
GetItemBits(sal_uInt16 nItemId) const1207 HeaderBarItemBits HeaderBar::GetItemBits( sal_uInt16 nItemId ) const
1208 {
1209     sal_uInt16 nPos = GetItemPos( nItemId );
1210     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1211         return mvItemList[ nPos ]->mnBits;
1212     else
1213         return HeaderBarItemBits::NONE;
1214 }
1215 
SetItemText(sal_uInt16 nItemId,const OUString & rText)1216 void HeaderBar::SetItemText( sal_uInt16 nItemId, const OUString& rText )
1217 {
1218     sal_uInt16 nPos = GetItemPos( nItemId );
1219     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1220     {
1221         mvItemList[ nPos ]->maText = rText;
1222         ImplUpdate( nPos );
1223     }
1224 }
1225 
GetItemText(sal_uInt16 nItemId) const1226 OUString HeaderBar::GetItemText( sal_uInt16 nItemId ) const
1227 {
1228     sal_uInt16 nPos = GetItemPos( nItemId );
1229     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1230         return mvItemList[ nPos ]->maText;
1231     return OUString();
1232 }
1233 
GetHelpText(sal_uInt16 nItemId) const1234 OUString HeaderBar::GetHelpText( sal_uInt16 nItemId ) const
1235 {
1236     sal_uInt16 nPos = GetItemPos( nItemId );
1237     if ( nPos != HEADERBAR_ITEM_NOTFOUND )
1238     {
1239         auto& pItem = mvItemList[ nPos ];
1240         if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() )
1241         {
1242             Help* pHelp = Application::GetHelp();
1243             if ( pHelp )
1244                 pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this );
1245         }
1246 
1247         return pItem->maHelpText;
1248     }
1249 
1250     return OUString();
1251 }
1252 
CalcWindowSizePixel() const1253 Size HeaderBar::CalcWindowSizePixel() const
1254 {
1255     tools::Long nMaxImageSize = 0;
1256     Size aSize( 0, GetTextHeight() );
1257 
1258     for (auto& pItem : mvItemList)
1259     {
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;
1266 
1267         // add width
1268         aSize.AdjustWidth(pItem->mnSize );
1269     }
1270 
1271     if ( nMaxImageSize > aSize.Height() )
1272         aSize.setHeight( nMaxImageSize );
1273 
1274     // add border
1275     if ( mbButtonStyle )
1276         aSize.AdjustHeight(4 );
1277     else
1278         aSize.AdjustHeight(2 );
1279     aSize.AdjustHeight(mnBorderOff1+mnBorderOff2 );
1280 
1281     return aSize;
1282 }
1283 
CreateAccessible()1284 css::uno::Reference< css::accessibility::XAccessible > HeaderBar::CreateAccessible()
1285 {
1286     if ( !mxAccessible.is() )
1287     {
1288         maCreateAccessibleHdl.Call( this );
1289 
1290         if ( !mxAccessible.is() )
1291             mxAccessible = Window::CreateAccessible();
1292     }
1293 
1294     return mxAccessible;
1295 }
1296 
SetAccessible(const css::uno::Reference<css::accessibility::XAccessible> & _xAccessible)1297 void HeaderBar::SetAccessible( const css::uno::Reference< css::accessibility::XAccessible >& _xAccessible )
1298 {
1299     mxAccessible = _xAccessible;
1300 }
1301 
1302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1303