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