LibreOffice Module vcl (master)  1
tabctrl.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 #include <sal/log.hxx>
22 
24 #include <vcl/svapp.hxx>
25 #include <vcl/help.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/menu.hxx>
28 #include <vcl/toolkit/button.hxx>
29 #include <vcl/tabpage.hxx>
30 #include <vcl/tabctrl.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <vcl/layout.hxx>
33 #include <vcl/toolkit/lstbox.hxx>
34 #include <vcl/settings.hxx>
35 #include <vcl/uitest/uiobject.hxx>
36 #include <bitmaps.hlst>
37 #include <tools/json_writer.hxx>
38 
39 #include <svdata.hxx>
40 #include <window.h>
41 
42 #include <deque>
43 #include <unordered_map>
44 #include <vector>
45 
46 class ImplTabItem final
47 {
48  sal_uInt16 m_nId;
49 
50 public:
52  OUString maText;
53  OUString maFormatText;
54  OUString maHelpText;
55  OUString maAccessibleName;
57  OString maTabName;
59  sal_uInt16 mnLine;
61  bool m_bEnabled;
62  bool m_bVisible;
64 
65  ImplTabItem(sal_uInt16 nId);
66 
67  sal_uInt16 id() const { return m_nId; }
68 };
69 
70 ImplTabItem::ImplTabItem(sal_uInt16 nId)
71  : m_nId(nId)
72  , mnLine(0)
73  , mbFullVisible(false)
74  , m_bEnabled(true)
75  , m_bVisible(true)
76 {
77 }
78 
80 {
81  std::unordered_map< int, int > maLayoutPageIdToLine;
82  std::unordered_map< int, int > maLayoutLineToPageId;
83  std::vector< ImplTabItem > maItemList;
85 };
86 
87 // for the Tab positions
88 #define TAB_PAGERECT 0xFFFF
89 
90 void TabControl::ImplInit( vcl::Window* pParent, WinBits nStyle )
91 {
92  mbLayoutDirty = true;
93 
94  if ( !(nStyle & WB_NOTABSTOP) )
95  nStyle |= WB_TABSTOP;
96  if ( !(nStyle & WB_NOGROUP) )
97  nStyle |= WB_GROUP;
98  if ( !(nStyle & WB_NODIALOGCONTROL) )
99  nStyle |= WB_DIALOGCONTROL;
100 
101  Control::ImplInit( pParent, nStyle, nullptr );
102 
103  mnLastWidth = 0;
104  mnLastHeight = 0;
105  mnActPageId = 0;
106  mnCurPageId = 0;
107  mbFormat = true;
108  mbRestoreHelpId = false;
109  mbSmallInvalidate = false;
110  mpTabCtrlData.reset(new ImplTabCtrlData);
111  mpTabCtrlData->mpListBox = nullptr;
112 
113  ImplInitSettings( true );
114 
115  if( nStyle & WB_DROPDOWN )
116  {
117  mpTabCtrlData->mpListBox = VclPtr<ListBox>::Create( this, WB_DROPDOWN );
118  mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
119  mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
120  mpTabCtrlData->mpListBox->Show();
121  }
122 
123  // if the tabcontrol is drawn (ie filled) by a native widget, make sure all controls will have transparent background
124  // otherwise they will paint with a wrong background
127 
128  if (pParent && pParent->IsDialog())
129  pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
130 }
131 
133 {
134  return _rStyle.GetTabFont();
135 }
136 
138 {
139  return _rStyle.GetTabTextColor();
140 }
141 
142 void TabControl::ImplInitSettings( bool bBackground )
143 {
145 
146  if ( !bBackground )
147  return;
148 
149  vcl::Window* pParent = GetParent();
150  if ( !IsControlBackground() &&
154 
155  {
156  // set transparent mode for NWF tabcontrols to have
157  // the background always cleared properly
160  SetPaintTransparent( true );
161  SetBackground();
163  }
164  else
165  {
168  SetPaintTransparent( false );
169 
170  if ( IsControlBackground() )
172  else
173  SetBackground( pParent->GetBackground() );
174  }
175 }
176 
178 {
179  if( HasLayoutData() )
180  {
182  mpTabCtrlData->maLayoutPageIdToLine.clear();
183  mpTabCtrlData->maLayoutLineToPageId.clear();
184  }
185 }
186 
189 {
190  ImplInit( pParent, nStyle );
191  SAL_INFO( "vcl", "*** TABCONTROL no notabs? " << (( GetStyle() & WB_NOBORDER ) ? "true" : "false") );
192 }
193 
195 {
196  disposeOnce();
197 }
198 
200 {
201  Window *pParent = GetParent();
202  if (pParent && pParent->IsDialog())
203  GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
204 
206 
207  // delete TabCtrl data
208  if (mpTabCtrlData)
209  mpTabCtrlData->mpListBox.disposeAndClear();
210  mpTabCtrlData.reset();
212 }
213 
214 ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const
215 {
216  for (auto & item : mpTabCtrlData->maItemList)
217  {
218  if (item.id() == nId)
219  return &item;
220  }
221 
222  return nullptr;
223 }
224 
226 {
227  pItem->maFormatText = pItem->maText;
228  Size aSize( GetOutDev()->GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
229  Size aImageSize( 0, 0 );
230  if( !!pItem->maTabImage )
231  {
232  aImageSize = pItem->maTabImage.GetSizePixel();
233  if( !pItem->maFormatText.isEmpty() )
234  aImageSize.AdjustWidth(GetTextHeight()/4 );
235  }
236  aSize.AdjustWidth(aImageSize.Width() );
237  if( aImageSize.Height() > aSize.Height() )
238  aSize.setHeight( aImageSize.Height() );
239 
240  aSize.AdjustWidth(TAB_TABOFFSET_X*2 );
241  aSize.AdjustHeight(TAB_TABOFFSET_Y*2 );
242 
243  tools::Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
244  tools::Rectangle aBoundingRgn, aContentRgn;
246  aSize.Width() - TAB_TABOFFSET_X * 2,
247  aSize.Height() - TAB_TABOFFSET_Y * 2));
249  ControlState::ENABLED, aControlValue,
250  aBoundingRgn, aContentRgn ) )
251  {
252  return aContentRgn.GetSize();
253  }
254 
255  // For languages with short names (e.g. Chinese), because the space is
256  // normally only one pixel per char
257  if ( pItem->maFormatText.getLength() < TAB_EXTRASPACE_X )
258  aSize.AdjustWidth(TAB_EXTRASPACE_X-pItem->maFormatText.getLength() );
259 
260  // shorten Text if needed
261  if ( aSize.Width()+4 >= nMaxWidth )
262  {
263  OUString aAppendStr("...");
264  pItem->maFormatText += aAppendStr;
265  do
266  {
267  if (pItem->maFormatText.getLength() > aAppendStr.getLength())
268  pItem->maFormatText = pItem->maFormatText.replaceAt( pItem->maFormatText.getLength()-aAppendStr.getLength()-1, 1, u"" );
269  aSize.setWidth( GetOutDev()->GetCtrlTextWidth( pItem->maFormatText ) );
270  aSize.AdjustWidth(aImageSize.Width() );
271  aSize.AdjustWidth(TAB_TABOFFSET_X*2 );
272  }
273  while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.getLength() > aAppendStr.getLength()) );
274  if ( aSize.Width()+4 >= nMaxWidth )
275  {
276  pItem->maFormatText = ".";
277  aSize.setWidth( 1 );
278  }
279  }
280 
281  if( pItem->maFormatText.isEmpty() )
282  {
283  if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
284  aSize.setHeight( aImageSize.Height()+4 );
285  }
286 
287  return aSize;
288 }
289 
290 // Feel free to move this to some more general place for reuse
291 // http://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
292 // Mostly based on Alexey Frunze's nifty example at
293 // http://stackoverflow.com/questions/9071205/balanced-word-wrap-minimum-raggedness-in-php
295 {
296  static std::deque<size_t> GetEndOfLineIndexes(const std::vector<sal_Int32>& rWidthsOf, sal_Int32 nLineWidth)
297  {
298  ++nLineWidth;
299 
300  size_t nWidthsCount = rWidthsOf.size();
301  std::vector<sal_Int32> aCosts(nWidthsCount * nWidthsCount);
302 
303  // cost function c(i, j) that computes the cost of a line consisting of
304  // the words Word[i] to Word[j]
305  for (size_t i = 0; i < nWidthsCount; ++i)
306  {
307  for (size_t j = 0; j < nWidthsCount; ++j)
308  {
309  if (j >= i)
310  {
311  sal_Int32 c = nLineWidth - (j - i);
312  for (size_t k = i; k <= j; ++k)
313  c -= rWidthsOf[k];
314  c = (c >= 0) ? c * c : SAL_MAX_INT32;
315  aCosts[j * nWidthsCount + i] = c;
316  }
317  else
318  {
319  aCosts[j * nWidthsCount + i] = SAL_MAX_INT32;
320  }
321  }
322  }
323 
324  std::vector<sal_Int32> aFunction(nWidthsCount);
325  std::vector<sal_Int32> aWrapPoints(nWidthsCount);
326 
327  // f(j) in aFunction[], collect wrap points in aWrapPoints[]
328  for (size_t j = 0; j < nWidthsCount; ++j)
329  {
330  aFunction[j] = aCosts[j * nWidthsCount];
331  if (aFunction[j] == SAL_MAX_INT32)
332  {
333  for (size_t k = 0; k < j; ++k)
334  {
335  sal_Int32 s;
336  if (aFunction[k] == SAL_MAX_INT32 || aCosts[j * nWidthsCount + k + 1] == SAL_MAX_INT32)
337  s = SAL_MAX_INT32;
338  else
339  s = aFunction[k] + aCosts[j * nWidthsCount + k + 1];
340  if (aFunction[j] > s)
341  {
342  aFunction[j] = s;
343  aWrapPoints[j] = k + 1;
344  }
345  }
346  }
347  }
348 
349  std::deque<size_t> aSolution;
350 
351  // no solution
352  if (aFunction[nWidthsCount - 1] == SAL_MAX_INT32)
353  return aSolution;
354 
355  // optimal solution
356  size_t j = nWidthsCount - 1;
357  while (true)
358  {
359  aSolution.push_front(j);
360  if (!aWrapPoints[j])
361  break;
362  j = aWrapPoints[j] - 1;
363  }
364 
365  return aSolution;
366  }
367 };
368 
369 static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
370 {
371  if (!ImplGetSVData()->maNWFData.mbCenteredTabs)
372  return;
373 
374  int nRightSpace = nMaxWidth; // space left on the right by the tabs
375  for (auto const& item : pTabCtrlData->maItemList)
376  {
377  if (!item.m_bVisible)
378  continue;
379  nRightSpace -= item.maRect.Right() - item.maRect.Left();
380  }
381  nRightSpace /= 2;
382 
383  for (auto& item : pTabCtrlData->maItemList)
384  {
385  if (!item.m_bVisible)
386  continue;
387  item.maRect.AdjustLeft(nRightSpace);
388  item.maRect.AdjustRight(nRightSpace);
389  }
390 }
391 
393 {
394  if ( nWidth <= 0 )
395  return false;
396  if ( mpTabCtrlData->maItemList.empty() )
397  return false;
398 
399  tools::Long nMaxWidth = nWidth;
400 
401  const tools::Long nOffsetX = 2;
402  const tools::Long nOffsetY = 2;
403 
404  //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
405  //of ugly bare tabs on lines of their own
406 
407  //collect widths
408  std::vector<sal_Int32> aWidths;
409  for (auto & item : mpTabCtrlData->maItemList)
410  {
411  if (!item.m_bVisible)
412  continue;
413  aWidths.push_back(ImplGetItemSize(&item, nMaxWidth).Width());
414  }
415 
416  //aBreakIndexes will contain the indexes of the last tab on each row
417  std::deque<size_t> aBreakIndexes(MinimumRaggednessWrap::GetEndOfLineIndexes(aWidths, nMaxWidth - nOffsetX - 2));
418 
419  tools::Long nX = nOffsetX;
420  tools::Long nY = nOffsetY;
421 
422  sal_uInt16 nLines = 0;
423  sal_uInt16 nCurLine = 0;
424 
425  tools::Long nLineWidthAry[100];
426  sal_uInt16 nLinePosAry[101];
427  nLineWidthAry[0] = 0;
428  nLinePosAry[0] = 0;
429 
430  size_t nIndex = 0;
431 
432  for (auto & item : mpTabCtrlData->maItemList)
433  {
434  if (!item.m_bVisible)
435  continue;
436 
437  Size aSize = ImplGetItemSize( &item, nMaxWidth );
438 
439  bool bNewLine = false;
440  if (!aBreakIndexes.empty() && nIndex > aBreakIndexes.front())
441  {
442  aBreakIndexes.pop_front();
443  bNewLine = true;
444  }
445 
446  if ( bNewLine && (nWidth > 2+nOffsetX) )
447  {
448  if ( nLines == 99 )
449  break;
450 
451  nX = nOffsetX;
452  nY += aSize.Height();
453  nLines++;
454  nLineWidthAry[nLines] = 0;
455  nLinePosAry[nLines] = nIndex;
456  }
457 
458  tools::Rectangle aNewRect( Point( nX, nY ), aSize );
459  if ( mbSmallInvalidate && (item.maRect != aNewRect) )
460  mbSmallInvalidate = false;
461  item.maRect = aNewRect;
462  item.mnLine = nLines;
463  item.mbFullVisible = true;
464 
465  nLineWidthAry[nLines] += aSize.Width();
466  nX += aSize.Width();
467 
468  if (item.id() == mnCurPageId)
469  nCurLine = nLines;
470 
471  ++nIndex;
472  }
473 
474  if (nLines) // two or more lines
475  {
476  tools::Long nLineHeightAry[100];
477  tools::Long nIH = 0;
478  for (const auto& item : mpTabCtrlData->maItemList)
479  {
480  if (!item.m_bVisible)
481  continue;
482  nIH = item.maRect.Bottom() - 1;
483  break;
484  }
485 
486  for ( sal_uInt16 i = 0; i < nLines+1; i++ )
487  {
488  if ( i <= nCurLine )
489  nLineHeightAry[i] = nIH*(nLines-(nCurLine-i));
490  else
491  nLineHeightAry[i] = nIH*(i-nCurLine-1);
492  }
493 
494  nLinePosAry[nLines+1] = static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
495 
496  tools::Long nDX = 0;
497  tools::Long nModDX = 0;
498  tools::Long nIDX = 0;
499 
500  sal_uInt16 i = 0;
501  sal_uInt16 n = 0;
502 
503  for (auto & item : mpTabCtrlData->maItemList)
504  {
505  if (!item.m_bVisible)
506  continue;
507 
508  if ( i == nLinePosAry[n] )
509  {
510  if ( n == nLines+1 )
511  break;
512 
513  nIDX = 0;
514  if( nLinePosAry[n+1]-i > 0 )
515  {
516  nDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) / ( nLinePosAry[n+1] - i );
517  nModDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) % ( nLinePosAry[n+1] - i );
518  }
519  else
520  {
521  // FIXME: this is a case of tabctrl way too small
522  nDX = 0;
523  nModDX = 0;
524  }
525  n++;
526  }
527 
528  item.maRect.AdjustLeft(nIDX );
529  item.maRect.AdjustRight(nIDX + nDX );
530  item.maRect.SetTop( nLineHeightAry[n-1] );
531  item.maRect.SetBottom(nLineHeightAry[n-1] + nIH - 1);
532  nIDX += nDX;
533 
534  if ( nModDX )
535  {
536  nIDX++;
537  item.maRect.AdjustRight( 1 );
538  nModDX--;
539  }
540 
541  i++;
542  }
543  }
544  else // only one line
545  lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
546 
547  return true;
548 }
549 
551 {
552  Size aWinSize = Control::GetOutputSizePixel();
553  if ( nWidth < 0 )
554  nWidth = aWinSize.Width();
555  if ( nHeight < 0 )
556  nHeight = aWinSize.Height();
557 
558  if ( mpTabCtrlData->maItemList.empty() )
559  {
560  tools::Long nW = nWidth-TAB_OFFSET*2;
561  tools::Long nH = nHeight-TAB_OFFSET*2;
562  return (nW > 0 && nH > 0)
563  ? tools::Rectangle(Point(TAB_OFFSET, TAB_OFFSET), Size(nW, nH))
564  : tools::Rectangle();
565  }
566 
567  if ( nItemPos == TAB_PAGERECT )
568  {
569  sal_uInt16 nLastPos;
570  if ( mnCurPageId )
571  nLastPos = GetPagePos( mnCurPageId );
572  else
573  nLastPos = 0;
574 
575  tools::Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
576  if (aRect.IsEmpty())
577  return aRect;
578 
579  tools::Long nW = nWidth-TAB_OFFSET*2;
580  tools::Long nH = nHeight-aRect.Bottom()-TAB_OFFSET*2;
581  return (nW > 0 && nH > 0)
582  ? tools::Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ), Size( nW, nH ) )
583  : tools::Rectangle();
584  }
585 
586  ImplTabItem* const pItem = (nItemPos < mpTabCtrlData->maItemList.size())
587  ? &mpTabCtrlData->maItemList[nItemPos] : nullptr;
588  return ImplGetTabRect(pItem, nWidth, nHeight);
589 }
590 
592 {
593  if ((nWidth <= 1) || (nHeight <= 0) || !pItem || !pItem->m_bVisible)
594  return tools::Rectangle();
595 
596  nWidth -= 1;
597 
598  if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
599  {
600  vcl::Font aFont( GetFont() );
601  aFont.SetTransparent( true );
602  SetFont( aFont );
603 
604  bool bRet = ImplPlaceTabs( nWidth );
605  if ( !bRet )
606  return tools::Rectangle();
607 
608  mnLastWidth = nWidth;
609  mnLastHeight = nHeight;
610  mbFormat = false;
611  }
612 
613  return pItem->maRect;
614 }
615 
616 void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId )
617 {
619 
620  ImplTabItem* pOldItem = ImplGetItem( nOldId );
621  ImplTabItem* pItem = ImplGetItem( nId );
622  TabPage* pOldPage = pOldItem ? pOldItem->mpTabPage.get() : nullptr;
623  TabPage* pPage = pItem ? pItem->mpTabPage.get() : nullptr;
624  vcl::Window* pCtrlParent = GetParent();
625 
626  if ( IsReallyVisible() && IsUpdateMode() )
627  {
628  sal_uInt16 nPos = GetPagePos( nId );
629  tools::Rectangle aRect = ImplGetTabRect( nPos );
630 
631  if ( !pOldItem || !pItem || (pOldItem->mnLine != pItem->mnLine) )
632  {
633  aRect.SetLeft( 0 );
634  aRect.SetTop( 0 );
636  }
637  else
638  {
639  aRect.AdjustLeft( -3 );
640  aRect.AdjustTop( -2 );
641  aRect.AdjustRight(3 );
642  Invalidate( aRect );
643  nPos = GetPagePos( nOldId );
644  aRect = ImplGetTabRect( nPos );
645  aRect.AdjustLeft( -3 );
646  aRect.AdjustTop( -2 );
647  aRect.AdjustRight(3 );
648  }
649  Invalidate( aRect );
650  }
651 
652  if ( pOldPage == pPage )
653  return;
654 
656 
657  if ( pOldPage )
658  {
659  if ( mbRestoreHelpId )
660  pCtrlParent->SetHelpId( OString() );
661  }
662 
663  if ( pPage )
664  {
665  if ( GetStyle() & WB_NOBORDER )
666  {
667  tools::Rectangle aRectNoTab(Point(0, 0), GetSizePixel());
668  pPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
669  }
670  else
671  pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
672 
673  // activate page here so the controls can be switched
674  // also set the help id of the parent window to that of the tab page
675  if ( GetHelpId().isEmpty() )
676  {
677  mbRestoreHelpId = true;
678  pCtrlParent->SetHelpId( pPage->GetHelpId() );
679  }
680 
681  pPage->Show();
682 
683  if ( pOldPage && pOldPage->HasChildPathFocus() )
684  {
685  vcl::Window* pFirstChild = pPage->ImplGetDlgWindow( 0, GetDlgWindowType::First );
686  if ( pFirstChild )
687  pFirstChild->ImplControlFocus( GetFocusFlags::Init );
688  else
689  GrabFocus();
690  }
691  }
692 
693  if ( pOldPage )
694  pOldPage->Hide();
695 
696  // Invalidate the same region that will be send to NWF
697  // to always allow for bitmap caching
698  // see Window::DrawNativeControl()
700  {
701  aRect.AdjustLeft( -(TAB_OFFSET) );
702  aRect.AdjustTop( -(TAB_OFFSET) );
703  aRect.AdjustRight(TAB_OFFSET );
704  aRect.AdjustBottom(TAB_OFFSET );
705  }
706 
707  Invalidate( aRect );
708 }
709 
711 {
712  // resize/position current TabPage
713  ImplTabItem* pItem = ImplGetItem( GetCurPageId() );
714  if ( pItem && pItem->mpTabPage )
715  {
716  if ( GetStyle() & WB_NOBORDER )
717  {
718  tools::Rectangle aRectNoTab(Point(0, 0), GetSizePixel());
719  pItem->mpTabPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
720  return true;
721  }
723  pItem->mpTabPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
724  return true;
725  }
726 
727  return false;
728 }
729 
731 {
732  sal_uInt16 nCurPos = GetPagePos( GetCurPageId() );
733 
734  if ( bNext )
735  nCurPos = (nCurPos + 1) % GetPageCount();
736  else
737  {
738  if ( !nCurPos )
739  nCurPos = GetPageCount()-1;
740  else
741  nCurPos--;
742  }
743 
744  SelectTabPage( GetPageId( nCurPos ) );
745 }
746 
748 {
749  if ( !GetPageCount() || mpTabCtrlData->mpListBox )
750  return;
751 
752  sal_uInt16 nCurPos = GetPagePos( mnCurPageId );
753  tools::Rectangle aRect = ImplGetTabRect( nCurPos );
754  const ImplTabItem& rItem = mpTabCtrlData->maItemList[ nCurPos ];
755  Size aTabSize = aRect.GetSize();
756  Size aImageSize( 0, 0 );
757  tools::Long nTextHeight = GetTextHeight();
758  tools::Long nTextWidth = GetOutDev()->GetCtrlTextWidth( rItem.maFormatText );
759  sal_uInt16 nOff;
760 
761  if ( !(GetSettings().GetStyleSettings().GetOptions() & StyleSettingsOptions::Mono) )
762  nOff = 1;
763  else
764  nOff = 0;
765 
766  if( !! rItem.maTabImage )
767  {
768  aImageSize = rItem.maTabImage.GetSizePixel();
769  if( !rItem.maFormatText.isEmpty() )
770  aImageSize.AdjustWidth(GetTextHeight()/4 );
771  }
772 
773  if( !rItem.maFormatText.isEmpty() )
774  {
775  // show focus around text
776  aRect.SetLeft( aRect.Left()+aImageSize.Width()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1-1 );
777  aRect.SetTop( aRect.Top()+((aTabSize.Height()-nTextHeight)/2)-1-1 );
778  aRect.SetRight( aRect.Left()+nTextWidth+2 );
779  aRect.SetBottom( aRect.Top()+nTextHeight+2 );
780  }
781  else
782  {
783  // show focus around image
784  tools::Long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
785  tools::Long nYPos = aRect.Top();
786  if( aImageSize.Height() < aRect.GetHeight() )
787  nYPos += (aRect.GetHeight() - aImageSize.Height())/2;
788 
789  aRect.SetLeft( nXPos - 2 );
790  aRect.SetTop( nYPos - 2 );
791  aRect.SetRight( aRect.Left() + aImageSize.Width() + 4 );
792  aRect.SetBottom( aRect.Top() + aImageSize.Height() + 4 );
793  }
794  ShowFocus( aRect );
795 }
796 
797 void TabControl::ImplDrawItem(vcl::RenderContext& rRenderContext, ImplTabItem const * pItem, const tools::Rectangle& rCurRect,
798  bool bFirstInGroup, bool bLastInGroup )
799 {
800  if (!pItem->m_bVisible || pItem->maRect.IsEmpty())
801  return;
802 
803  const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
804  tools::Rectangle aRect = pItem->maRect;
805  tools::Long nLeftBottom = aRect.Bottom();
806  tools::Long nRightBottom = aRect.Bottom();
807  bool bLeftBorder = true;
808  bool bRightBorder = true;
809  sal_uInt16 nOff;
810  bool bNativeOK = false;
811 
812  sal_uInt16 nOff2 = 0;
813  sal_uInt16 nOff3 = 0;
814 
815  if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
816  nOff = 1;
817  else
818  nOff = 0;
819 
820  // if this is the active Page, we have to draw a little more
821  if (pItem->id() == mnCurPageId)
822  {
823  nOff2 = 2;
825  nOff3 = 1;
826  }
827  else
828  {
829  Point aLeftTestPos = aRect.BottomLeft();
830  Point aRightTestPos = aRect.BottomRight();
831  if (aLeftTestPos.Y() == rCurRect.Bottom())
832  {
833  aLeftTestPos.AdjustX( -2 );
834  if (rCurRect.Contains(aLeftTestPos))
835  bLeftBorder = false;
836  aRightTestPos.AdjustX(2 );
837  if (rCurRect.Contains(aRightTestPos))
838  bRightBorder = false;
839  }
840  else
841  {
842  if (rCurRect.Contains(aLeftTestPos))
843  nLeftBottom -= 2;
844  if (rCurRect.Contains(aRightTestPos))
845  nRightBottom -= 2;
846  }
847  }
848 
850 
851  if (pItem->id() == mnCurPageId)
852  {
853  nState |= ControlState::SELECTED;
854  // only the selected item can be focused
855  if (HasFocus())
856  nState |= ControlState::FOCUSED;
857  }
858  if (IsEnabled())
859  nState |= ControlState::ENABLED;
860  if (IsMouseOver() && pItem->maRect.Contains(GetPointerPosPixel()))
861  {
862  nState |= ControlState::ROLLOVER;
863  for (auto const& item : mpTabCtrlData->maItemList)
864  if ((&item != pItem) && item.m_bVisible && item.maRect.Contains(GetPointerPosPixel()))
865  {
866  nState &= ~ControlState::ROLLOVER; // avoid multiple highlighted tabs
867  break;
868  }
869  assert(nState & ControlState::ROLLOVER);
870  }
871 
873  if ( bNativeOK )
874  {
876  pItem->maRect.Top() + TAB_TABOFFSET_Y,
877  pItem->maRect.Right() - TAB_TABOFFSET_X,
878  pItem->maRect.Bottom() - TAB_TABOFFSET_Y));
879  if (pItem->maRect.Left() < 5)
881  if (pItem->maRect.Right() > mnLastWidth - 5)
883  if (bFirstInGroup)
885  if (bLastInGroup)
887 
888  tools::Rectangle aCtrlRegion( pItem->maRect );
890  bNativeOK = rRenderContext.DrawNativeControl(ControlType::TabItem, ControlPart::Entire,
891  aCtrlRegion, nState, tiValue, OUString() );
892  }
893 
894  if (!bNativeOK)
895  {
896  if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
897  {
898  rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
899  rRenderContext.DrawPixel(Point(aRect.Left() + 1 - nOff2, aRect.Top() + 1 - nOff2)); // diagonally indented top-left pixel
900  if (bLeftBorder)
901  {
902  rRenderContext.DrawLine(Point(aRect.Left() - nOff2, aRect.Top() + 2 - nOff2),
903  Point(aRect.Left() - nOff2, nLeftBottom - 1));
904  }
905  rRenderContext.DrawLine(Point(aRect.Left() + 2 - nOff2, aRect.Top() - nOff2), // top line starting 2px from left border
906  Point(aRect.Right() + nOff2 - 3, aRect.Top() - nOff2)); // ending 3px from right border
907 
908  if (bRightBorder)
909  {
910  rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
911  rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 2, aRect.Top() + 1 - nOff2),
912  Point(aRect.Right() + nOff2 - 2, nRightBottom - 1));
913 
914  rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
915  rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 1, aRect.Top() + 3 - nOff2),
916  Point(aRect.Right() + nOff2 - 1, nRightBottom - 1));
917  }
918  }
919  else
920  {
921  rRenderContext.SetLineColor(COL_BLACK);
922  rRenderContext.DrawPixel(Point(aRect.Left() + 1 - nOff2, aRect.Top() + 1 - nOff2));
923  rRenderContext.DrawPixel(Point(aRect.Right() + nOff2 - 2, aRect.Top() + 1 - nOff2));
924  if (bLeftBorder)
925  {
926  rRenderContext.DrawLine(Point(aRect.Left() - nOff2, aRect.Top() + 2 - nOff2),
927  Point(aRect.Left() - nOff2, nLeftBottom - 1));
928  }
929  rRenderContext.DrawLine(Point(aRect.Left() + 2 - nOff2, aRect.Top() - nOff2),
930  Point(aRect.Right() - 3, aRect.Top() - nOff2));
931  if (bRightBorder)
932  {
933  rRenderContext.DrawLine(Point(aRect.Right() + nOff2 - 1, aRect.Top() + 2 - nOff2),
934  Point(aRect.Right() + nOff2 - 1, nRightBottom - 1));
935  }
936  }
937  }
938 
939  // set font accordingly, current item is painted bold
940  // we set the font attributes always before drawing to be re-entrant (DrawNativeControl may trigger additional paints)
941  vcl::Font aFont(rRenderContext.GetFont());
942  aFont.SetTransparent(true);
943  rRenderContext.SetFont(aFont);
944 
945  Size aTabSize = aRect.GetSize();
946  Size aImageSize(0, 0);
947  tools::Long nTextHeight = rRenderContext.GetTextHeight();
948  tools::Long nTextWidth = rRenderContext.GetCtrlTextWidth(pItem->maFormatText);
949  if (!!pItem->maTabImage)
950  {
951  aImageSize = pItem->maTabImage.GetSizePixel();
952  if (!pItem->maFormatText.isEmpty())
953  aImageSize.AdjustWidth(GetTextHeight() / 4 );
954  }
955  tools::Long nXPos = aRect.Left() + ((aTabSize.Width() - nTextWidth - aImageSize.Width()) / 2) - nOff - nOff3;
956  tools::Long nYPos = aRect.Top() + ((aTabSize.Height() - nTextHeight) / 2) - nOff3;
957  if (!pItem->maFormatText.isEmpty())
958  {
960  if (!pItem->m_bEnabled)
961  nStyle |= DrawTextFlags::Disable;
962 
963  Color aColor(rStyleSettings.GetTabTextColor());
964  if (nState & ControlState::SELECTED)
965  aColor = rStyleSettings.GetTabHighlightTextColor();
966  else if (nState & ControlState::ROLLOVER)
967  aColor = rStyleSettings.GetTabRolloverTextColor();
968 
969  Color aOldColor(rRenderContext.GetTextColor());
970  rRenderContext.SetTextColor(aColor);
971 
972  const tools::Rectangle aOutRect(nXPos + aImageSize.Width(), nYPos,
973  nXPos + aImageSize.Width() + nTextWidth, nYPos + nTextHeight);
974  DrawControlText(rRenderContext, aOutRect, pItem->maFormatText, nStyle,
975  nullptr, nullptr);
976 
977  rRenderContext.SetTextColor(aOldColor);
978  }
979 
980  if (!!pItem->maTabImage)
981  {
982  Point aImgTL( nXPos, aRect.Top() );
983  if (aImageSize.Height() < aRect.GetHeight())
984  aImgTL.AdjustY((aRect.GetHeight() - aImageSize.Height()) / 2 );
985  rRenderContext.DrawImage(aImgTL, pItem->maTabImage, pItem->m_bEnabled ? DrawImageFlags::NONE : DrawImageFlags::Disable );
986  }
987 }
988 
989 bool TabControl::ImplHandleKeyEvent( const KeyEvent& rKeyEvent )
990 {
991  bool bRet = false;
992 
993  if ( GetPageCount() > 1 )
994  {
995  vcl::KeyCode aKeyCode = rKeyEvent.GetKeyCode();
996  sal_uInt16 nKeyCode = aKeyCode.GetCode();
997 
998  if ( aKeyCode.IsMod1() )
999  {
1000  if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
1001  {
1002  if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
1003  {
1004  ImplActivateTabPage( false );
1005  bRet = true;
1006  }
1007  }
1008  else
1009  {
1010  if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
1011  {
1012  ImplActivateTabPage( true );
1013  bRet = true;
1014  }
1015  }
1016  }
1017  }
1018 
1019  return bRet;
1020 }
1021 
1022 IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl, ListBox&, void)
1023 {
1024  SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectedEntryPos() ) );
1025 }
1026 
1027 IMPL_LINK( TabControl, ImplWindowEventListener, VclWindowEvent&, rEvent, void )
1028 {
1029  if ( rEvent.GetId() == VclEventId::WindowKeyInput )
1030  {
1031  // Do not handle events from TabControl or its children, which is done in Notify(), where the events can be consumed.
1032  if ( !IsWindowOrChild( rEvent.GetWindow() ) )
1033  {
1034  KeyEvent* pKeyEvent = static_cast< KeyEvent* >(rEvent.GetData());
1035  ImplHandleKeyEvent( *pKeyEvent );
1036  }
1037  }
1038 }
1039 
1041 {
1042  if (mpTabCtrlData->mpListBox || !rMEvt.IsLeft())
1043  return;
1044 
1045  ImplTabItem *pItem = ImplGetItem(rMEvt.GetPosPixel());
1046  if (pItem && pItem->m_bEnabled)
1047  SelectTabPage(pItem->id());
1048 }
1049 
1050 void TabControl::KeyInput( const KeyEvent& rKEvt )
1051 {
1052  if( mpTabCtrlData->mpListBox )
1053  mpTabCtrlData->mpListBox->KeyInput( rKEvt );
1054  else if ( GetPageCount() > 1 )
1055  {
1056  vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1057  sal_uInt16 nKeyCode = aKeyCode.GetCode();
1058 
1059  if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_RIGHT) )
1060  {
1061  bool bNext = (nKeyCode == KEY_RIGHT);
1062  ImplActivateTabPage( bNext );
1063  }
1064  }
1065 
1066  Control::KeyInput( rKEvt );
1067 }
1068 
1069 static bool lcl_canPaint(const vcl::RenderContext& rRenderContext, const tools::Rectangle& rDrawRect,
1070  const tools::Rectangle& rItemRect)
1071 {
1072  vcl::Region aClipRgn(rRenderContext.GetActiveClipRegion());
1073  aClipRgn.Intersect(rItemRect);
1074  if (!rDrawRect.IsEmpty())
1075  aClipRgn.Intersect(rDrawRect);
1076  return !aClipRgn.IsEmpty();
1077 }
1078 
1079 void TabControl::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
1080 {
1081  if (GetStyle() & WB_NOBORDER)
1082  return;
1083 
1084  Control::Paint(rRenderContext, rRect);
1085 
1086  HideFocus();
1087 
1088  // reformat if needed
1090 
1091  // find current item
1092  ImplTabItem* pCurItem = nullptr;
1093  for (auto & item : mpTabCtrlData->maItemList)
1094  {
1095  if (item.id() == mnCurPageId)
1096  {
1097  pCurItem = &item;
1098  break;
1099  }
1100  }
1101 
1102  // Draw the TabPage border
1103  const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1104  tools::Rectangle aCurRect;
1105  aRect.AdjustLeft( -(TAB_OFFSET) );
1106  aRect.AdjustTop( -(TAB_OFFSET) );
1107  aRect.AdjustRight(TAB_OFFSET );
1108  aRect.AdjustBottom(TAB_OFFSET );
1109 
1110  // if we have an invisible tabpage or no tabpage at all the tabpage rect should be
1111  // increased to avoid round corners that might be drawn by a theme
1112  // in this case we're only interested in the top border of the tabpage because the tabitems are used
1113  // standalone (eg impress)
1114  bool bNoTabPage = false;
1115  TabPage* pCurPage = pCurItem ? pCurItem->mpTabPage.get() : nullptr;
1116  if (!pCurPage || !pCurPage->IsVisible())
1117  {
1118  bNoTabPage = true;
1119  aRect.AdjustLeft( -10 );
1120  aRect.AdjustRight(10 );
1121  }
1122 
1124  {
1125  const bool bPaneWithHeader = rRenderContext.IsNativeControlSupported(ControlType::TabPane, ControlPart::TabPaneWithHeader);
1126  tools::Rectangle aHeaderRect(aRect.Left(), 0, aRect.Right(), aRect.Top());
1127  if (bPaneWithHeader)
1128  {
1129  aRect.SetTop(0);
1130  if (mpTabCtrlData->maItemList.size())
1131  {
1132  tools::Long nRight = 0;
1133  for (const auto &item : mpTabCtrlData->maItemList)
1134  if (item.m_bVisible)
1135  nRight = item.maRect.Right();
1136  assert(nRight);
1137  aHeaderRect.SetRight(nRight);
1138  }
1139  }
1140  const TabPaneValue aTabPaneValue(aHeaderRect, pCurItem ? pCurItem->maRect : tools::Rectangle());
1141 
1143  if (!IsEnabled())
1144  nState &= ~ControlState::ENABLED;
1145  if (HasFocus())
1146  nState |= ControlState::FOCUSED;
1147 
1148  if (lcl_canPaint(rRenderContext, rRect, aRect))
1150  aRect, nState, aTabPaneValue, OUString());
1151 
1152  if (!bPaneWithHeader && rRenderContext.IsNativeControlSupported(ControlType::TabHeader, ControlPart::Entire)
1153  && lcl_canPaint(rRenderContext, rRect, aHeaderRect))
1155  aHeaderRect, nState, aTabPaneValue, OUString());
1156  }
1157  else
1158  {
1159  tools::Long nTopOff = 1;
1160  if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1161  rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
1162  else
1163  rRenderContext.SetLineColor(COL_BLACK);
1164  if (pCurItem && !pCurItem->maRect.IsEmpty())
1165  {
1166  aCurRect = pCurItem->maRect;
1167  rRenderContext.DrawLine(aRect.TopLeft(), Point(aCurRect.Left() - 2, aRect.Top()));
1168  if (aCurRect.Right() + 1 < aRect.Right())
1169  {
1170  rRenderContext.DrawLine(Point(aCurRect.Right(), aRect.Top()), aRect.TopRight());
1171  }
1172  else
1173  {
1174  nTopOff = 0;
1175  }
1176  }
1177  else
1178  rRenderContext.DrawLine(aRect.TopLeft(), aRect.TopRight());
1179 
1180  rRenderContext.DrawLine(aRect.TopLeft(), aRect.BottomLeft());
1181 
1182  if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1183  {
1184  // if we have not tab page the bottom line of the tab page
1185  // directly touches the tab items, so choose a color that fits seamlessly
1186  if (bNoTabPage)
1187  rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1188  else
1189  rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
1190  rRenderContext.DrawLine(Point(1, aRect.Bottom() - 1), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1191  rRenderContext.DrawLine(Point(aRect.Right() - 1, aRect.Top() + nTopOff), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1192  if (bNoTabPage)
1193  rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1194  else
1195  rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
1196  rRenderContext.DrawLine(Point(0, aRect.Bottom()), Point(aRect.Right(), aRect.Bottom()));
1197  rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top() + nTopOff), Point(aRect.Right(), aRect.Bottom()));
1198  }
1199  else
1200  {
1201  rRenderContext.DrawLine(aRect.TopRight(), aRect.BottomRight());
1202  rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
1203  }
1204  }
1205 
1206  if (!mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == nullptr)
1207  {
1208  // Some native toolkits (GTK+) draw tabs right-to-left, with an
1209  // overlap between adjacent tabs
1210  bool bDrawTabsRTL = rRenderContext.IsNativeControlSupported(ControlType::TabItem, ControlPart::TabsDrawRtl);
1211  ImplTabItem* pFirstTab = nullptr;
1212  ImplTabItem* pLastTab = nullptr;
1213  size_t idx;
1214 
1215  // Even though there is a tab overlap with GTK+, the first tab is not
1216  // overlapped on the left side. Other toolkits ignore this option.
1217  if (bDrawTabsRTL)
1218  {
1219  pFirstTab = mpTabCtrlData->maItemList.data();
1220  pLastTab = pFirstTab + mpTabCtrlData->maItemList.size() - 1;
1221  idx = mpTabCtrlData->maItemList.size() - 1;
1222  }
1223  else
1224  {
1225  pLastTab = mpTabCtrlData->maItemList.data();
1226  pFirstTab = pLastTab + mpTabCtrlData->maItemList.size() - 1;
1227  idx = 0;
1228  }
1229 
1230  while (idx < mpTabCtrlData->maItemList.size())
1231  {
1232  ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1233 
1234  if (pItem != pCurItem && pItem->m_bVisible && lcl_canPaint(rRenderContext, rRect, pItem->maRect))
1235  ImplDrawItem(rRenderContext, pItem, aCurRect, pItem == pFirstTab, pItem == pLastTab);
1236 
1237  if (bDrawTabsRTL)
1238  idx--;
1239  else
1240  idx++;
1241  }
1242 
1243  if (pCurItem && lcl_canPaint(rRenderContext, rRect, pCurItem->maRect))
1244  ImplDrawItem(rRenderContext, pCurItem, aCurRect, pCurItem == pFirstTab, pCurItem == pLastTab);
1245  }
1246 
1247  if (HasFocus())
1248  ImplShowFocus();
1249 
1250  mbSmallInvalidate = true;
1251 }
1252 
1253 void TabControl::setAllocation(const Size &rAllocation)
1254 {
1256 
1257  if ( !IsReallyShown() )
1258  return;
1259 
1260  if( mpTabCtrlData->mpListBox )
1261  {
1262  // get the listbox' preferred size
1263  Size aTabCtrlSize( GetSizePixel() );
1264  tools::Long nPrefWidth = mpTabCtrlData->mpListBox->get_preferred_size().Width();
1265  if( nPrefWidth > aTabCtrlSize.Width() )
1266  nPrefWidth = aTabCtrlSize.Width();
1267  Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MapUnit::MapAppFont ) ).Height() );
1268  Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
1269  mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
1270  }
1271 
1272  mbFormat = true;
1273 
1274  // resize/position active TabPage
1275  bool bTabPage = ImplPosCurTabPage();
1276 
1277  // check what needs to be invalidated
1278  Size aNewSize = rAllocation;
1279  tools::Long nNewWidth = aNewSize.Width();
1280  for (auto const& item : mpTabCtrlData->maItemList)
1281  {
1282  if (!item.m_bVisible)
1283  continue;
1284  if (!item.mbFullVisible || (item.maRect.Right()-2 >= nNewWidth))
1285  {
1286  mbSmallInvalidate = false;
1287  break;
1288  }
1289  }
1290 
1291  if ( mbSmallInvalidate )
1292  {
1295  aRect.AdjustTop( -(TAB_OFFSET+TAB_BORDER_TOP) );
1298  if ( bTabPage )
1300  else
1301  Invalidate( aRect );
1302 
1303  }
1304  else
1305  {
1306  if ( bTabPage )
1308  else
1309  Invalidate();
1310  }
1311 
1312  mbLayoutDirty = false;
1313 }
1314 
1315 void TabControl::SetPosSizePixel(const Point& rNewPos, const Size& rNewSize)
1316 {
1317  Window::SetPosSizePixel(rNewPos, rNewSize);
1318  //if size changed, TabControl::Resize got called already
1319  if (mbLayoutDirty)
1320  setAllocation(rNewSize);
1321 }
1322 
1323 void TabControl::SetSizePixel(const Size& rNewSize)
1324 {
1325  Window::SetSizePixel(rNewSize);
1326  //if size changed, TabControl::Resize got called already
1327  if (mbLayoutDirty)
1328  setAllocation(rNewSize);
1329 }
1330 
1331 void TabControl::SetPosPixel(const Point& rPos)
1332 {
1333  Window::SetPosPixel(rPos);
1334  if (mbLayoutDirty)
1336 }
1337 
1339 {
1341 }
1342 
1344 {
1345  if( ! mpTabCtrlData->mpListBox )
1346  {
1347  ImplShowFocus();
1349  }
1350  else
1351  {
1352  if( mpTabCtrlData->mpListBox->IsReallyVisible() )
1353  mpTabCtrlData->mpListBox->GrabFocus();
1354  }
1356 }
1357 
1359 {
1360  if( mpTabCtrlData && ! mpTabCtrlData->mpListBox )
1361  HideFocus();
1363 }
1364 
1366 {
1367  sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1368 
1369  if ( nItemId )
1370  {
1371  if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1372  {
1373  OUString aStr = GetHelpText( nItemId );
1374  if ( !aStr.isEmpty() )
1375  {
1376  tools::Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1377  Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1378  aItemRect.SetLeft( aPt.X() );
1379  aItemRect.SetTop( aPt.Y() );
1380  aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1381  aItemRect.SetRight( aPt.X() );
1382  aItemRect.SetBottom( aPt.Y() );
1383  Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1384  return;
1385  }
1386  }
1387 
1388  // for Quick or Ballon Help, we show the text, if it is cut
1390  {
1391  ImplTabItem* pItem = ImplGetItem( nItemId );
1392  const OUString& rStr = pItem->maText;
1393  if ( rStr != pItem->maFormatText )
1394  {
1395  tools::Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1396  Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1397  aItemRect.SetLeft( aPt.X() );
1398  aItemRect.SetTop( aPt.Y() );
1399  aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1400  aItemRect.SetRight( aPt.X() );
1401  aItemRect.SetBottom( aPt.Y() );
1402  if ( !rStr.isEmpty() )
1403  {
1404  if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1405  Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1406  else
1407  Help::ShowQuickHelp( this, aItemRect, rStr );
1408  return;
1409  }
1410  }
1411  }
1412 
1413  if ( rHEvt.GetMode() & HelpEventMode::QUICK )
1414  {
1415  ImplTabItem* pItem = ImplGetItem( nItemId );
1416  const OUString& rHelpText = pItem->maHelpText;
1417  if (!rHelpText.isEmpty())
1418  {
1419  tools::Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1420  Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1421  aItemRect.SetLeft( aPt.X() );
1422  aItemRect.SetTop( aPt.Y() );
1423  aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1424  aItemRect.SetRight( aPt.X() );
1425  aItemRect.SetBottom( aPt.Y() );
1426  Help::ShowQuickHelp( this, aItemRect, rHelpText );
1427  return;
1428  }
1429  }
1430  }
1431 
1432  Control::RequestHelp( rHEvt );
1433 }
1434 
1435 void TabControl::Command( const CommandEvent& rCEvt )
1436 {
1437  if( (mpTabCtrlData->mpListBox == nullptr) && (rCEvt.GetCommand() == CommandEventId::ContextMenu) && (GetPageCount() > 1) )
1438  {
1439  Point aMenuPos;
1440  bool bMenu;
1441  if ( rCEvt.IsMouseEvent() )
1442  {
1443  aMenuPos = rCEvt.GetMousePosPixel();
1444  bMenu = GetPageId( aMenuPos ) != 0;
1445  }
1446  else
1447  {
1448  aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1449  bMenu = true;
1450  }
1451 
1452  if ( bMenu )
1453  {
1455  for (auto const& item : mpTabCtrlData->maItemList)
1456  {
1457  aMenu->InsertItem(item.id(), item.maText, MenuItemBits::CHECKABLE | MenuItemBits::RADIOCHECK);
1458  if (item.id() == mnCurPageId)
1459  aMenu->CheckItem(item.id());
1460  aMenu->SetHelpId(item.id(), OString());
1461  }
1462 
1463  sal_uInt16 nId = aMenu->Execute( this, aMenuPos );
1464  if ( nId && (nId != mnCurPageId) )
1465  SelectTabPage( nId );
1466  return;
1467  }
1468  }
1469 
1470  Control::Command( rCEvt );
1471 }
1472 
1474 {
1475  Control::StateChanged( nType );
1476 
1477  if ( nType == StateChangedType::InitShow )
1478  {
1480  if( mpTabCtrlData->mpListBox )
1481  Resize();
1482  }
1483  else if ( nType == StateChangedType::UpdateMode )
1484  {
1485  if ( IsUpdateMode() )
1486  Invalidate();
1487  }
1488  else if ( (nType == StateChangedType::Zoom) ||
1489  (nType == StateChangedType::ControlFont) )
1490  {
1491  ImplInitSettings( false );
1492  Invalidate();
1493  }
1494  else if ( nType == StateChangedType::ControlForeground )
1495  {
1496  ImplInitSettings( false );
1497  Invalidate();
1498  }
1499  else if ( nType == StateChangedType::ControlBackground )
1500  {
1501  ImplInitSettings( true );
1502  Invalidate();
1503  }
1504 }
1505 
1507 {
1508  Control::DataChanged( rDCEvt );
1509 
1510  if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1512  ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1513  (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1514  {
1515  ImplInitSettings( true );
1516  Invalidate();
1517  }
1518 }
1519 
1520 ImplTabItem* TabControl::ImplGetItem(const Point& rPt) const
1521 {
1522  ImplTabItem* pFoundItem = nullptr;
1523  int nFound = 0;
1524  for (auto & item : mpTabCtrlData->maItemList)
1525  {
1526  if (item.m_bVisible && item.maRect.Contains(rPt))
1527  {
1528  nFound++;
1529  pFoundItem = &item;
1530  }
1531  }
1532 
1533  // assure that only one tab is highlighted at a time
1534  assert(nFound <= 1);
1535  return nFound == 1 ? pFoundItem : nullptr;
1536 }
1537 
1539 {
1540  if( rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE )
1541  {
1542  const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
1543  if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1544  {
1545  // trigger redraw if mouse over state has changed
1547  {
1550  if ((pItem != pLastItem) || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
1551  {
1552  vcl::Region aClipRgn;
1553  if (pLastItem)
1554  {
1555  // allow for slightly bigger tabitems
1556  // as used by gtk
1557  // TODO: query for the correct sizes
1558  tools::Rectangle aRect(pLastItem->maRect);
1559  aRect.AdjustLeft( -2 );
1560  aRect.AdjustRight(2 );
1561  aRect.AdjustTop( -3 );
1562  aClipRgn.Union( aRect );
1563  }
1564 
1565  if (pItem)
1566  {
1567  // allow for slightly bigger tabitems
1568  // as used by gtk
1569  // TODO: query for the correct sizes
1570  tools::Rectangle aRect(pItem->maRect);
1571  aRect.AdjustLeft( -2 );
1572  aRect.AdjustRight(2 );
1573  aRect.AdjustTop( -3 );
1574  aClipRgn.Union( aRect );
1575  }
1576 
1577  if( !aClipRgn.IsEmpty() )
1578  Invalidate( aClipRgn );
1579  }
1580  }
1581  }
1582  }
1583 
1584  return Control::PreNotify(rNEvt);
1585 }
1586 
1588 {
1589  bool bRet = false;
1590 
1591  if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
1592  bRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1593 
1594  return bRet || Control::EventNotify( rNEvt );
1595 }
1596 
1598 {
1599  maActivateHdl.Call( this );
1600 }
1601 
1603 {
1604  return !maDeactivateHdl.IsSet() || maDeactivateHdl.Call( this );
1605 }
1606 
1608 {
1610 
1611  Size aNewSize( rSize );
1612  aNewSize.AdjustWidth(TAB_OFFSET*2 );
1614  aNewSize.Width(), aNewSize.Height() );
1615  aNewSize.AdjustHeight(aRect.Top()+TAB_OFFSET );
1616  Window::SetOutputSizePixel( aNewSize );
1617 }
1618 
1619 void TabControl::InsertPage( sal_uInt16 nPageId, const OUString& rText,
1620  sal_uInt16 nPos )
1621 {
1622  SAL_WARN_IF( !nPageId, "vcl", "TabControl::InsertPage(): PageId == 0" );
1623  SAL_WARN_IF( GetPagePos( nPageId ) != TAB_PAGE_NOTFOUND, "vcl",
1624  "TabControl::InsertPage(): PageId already exists" );
1625 
1626  // insert new page item
1627  ImplTabItem* pItem = nullptr;
1628  if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1629  {
1630  mpTabCtrlData->maItemList.emplace_back(nPageId);
1631  pItem = &mpTabCtrlData->maItemList.back();
1632  if( mpTabCtrlData->mpListBox )
1633  mpTabCtrlData->mpListBox->InsertEntry( rText );
1634  }
1635  else
1636  {
1637  std::vector< ImplTabItem >::iterator new_it =
1638  mpTabCtrlData->maItemList.emplace(mpTabCtrlData->maItemList.begin() + nPos, nPageId);
1639  pItem = &(*new_it);
1640  if( mpTabCtrlData->mpListBox )
1641  mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1642  }
1643  if( mpTabCtrlData->mpListBox )
1644  {
1645  if( ! mnCurPageId )
1646  mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1647  mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1648  }
1649 
1650  // set current page id
1651  if ( !mnCurPageId )
1652  mnCurPageId = nPageId;
1653 
1654  // init new page item
1655  pItem->maText = rText;
1656  pItem->mbFullVisible = false;
1657 
1658  mbFormat = true;
1659  if ( IsUpdateMode() )
1660  Invalidate();
1661 
1663  if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1664  Resize();
1665 
1666  CallEventListeners( VclEventId::TabpageInserted, reinterpret_cast<void*>(nPageId) );
1667 }
1668 
1669 void TabControl::RemovePage( sal_uInt16 nPageId )
1670 {
1671  sal_uInt16 nPos = GetPagePos( nPageId );
1672 
1673  // does the item exist ?
1674  if ( nPos == TAB_PAGE_NOTFOUND )
1675  return;
1676 
1677  //remove page item
1678  std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1679  bool bIsCurrentPage = (it->id() == mnCurPageId);
1680  mpTabCtrlData->maItemList.erase( it );
1681  if( mpTabCtrlData->mpListBox )
1682  {
1683  mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1684  mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1685  }
1686 
1687  // If current page is removed, then first page gets the current page
1688  if ( bIsCurrentPage )
1689  {
1690  mnCurPageId = 0;
1691 
1692  if( ! mpTabCtrlData->maItemList.empty() )
1693  {
1694  // don't do this by simply setting mnCurPageId to pFirstItem->id()
1695  // this leaves a lot of stuff (such trivia as _showing_ the new current page) undone
1696  // instead, call SetCurPageId
1697  // without this, the next (outside) call to SetCurPageId with the id of the first page
1698  // will result in doing nothing (as we assume that nothing changed, then), and the page
1699  // will never be shown.
1700  // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1701 
1702  SetCurPageId(mpTabCtrlData->maItemList[0].id());
1703  }
1704  }
1705 
1706  mbFormat = true;
1707  if ( IsUpdateMode() )
1708  Invalidate();
1709 
1711 
1712  CallEventListeners( VclEventId::TabpageRemoved, reinterpret_cast<void*>(nPageId) );
1713 }
1714 
1715 void TabControl::SetPageEnabled( sal_uInt16 i_nPageId, bool i_bEnable )
1716 {
1717  ImplTabItem* pItem = ImplGetItem( i_nPageId );
1718 
1719  if (!pItem || pItem->m_bEnabled == i_bEnable)
1720  return;
1721 
1722  pItem->m_bEnabled = i_bEnable;
1723  if (!pItem->m_bVisible)
1724  return;
1725 
1726  mbFormat = true;
1727  if( mpTabCtrlData->mpListBox )
1728  mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1730 
1731  // SetCurPageId will change to a valid page
1732  if (pItem->id() == mnCurPageId)
1734  else if ( IsUpdateMode() )
1735  Invalidate();
1736 }
1737 
1738 void TabControl::SetPageVisible( sal_uInt16 nPageId, bool bVisible )
1739 {
1740  ImplTabItem* pItem = ImplGetItem( nPageId );
1741  if (!pItem || pItem->m_bVisible == bVisible)
1742  return;
1743 
1744  pItem->m_bVisible = bVisible;
1745  if (!bVisible)
1746  {
1747  if (pItem->mbFullVisible)
1748  mbSmallInvalidate = false;
1749  pItem->mbFullVisible = false;
1750  pItem->maRect.SetEmpty();
1751  }
1752  mbFormat = true;
1753 
1754  // SetCurPageId will change to a valid page
1755  if (pItem->id() == mnCurPageId)
1757  else if (IsUpdateMode())
1758  Invalidate();
1759 }
1760 
1761 sal_uInt16 TabControl::GetPageCount() const
1762 {
1763  return static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
1764 }
1765 
1766 sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1767 {
1768  if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1769  return mpTabCtrlData->maItemList[nPos].id();
1770  return 0;
1771 }
1772 
1773 sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1774 {
1775  sal_uInt16 nPos = 0;
1776  for (auto const& item : mpTabCtrlData->maItemList)
1777  {
1778  if (item.id() == nPageId)
1779  return nPos;
1780  ++nPos;
1781  }
1782 
1783  return TAB_PAGE_NOTFOUND;
1784 }
1785 
1786 sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1787 {
1788  Size winSize = Control::GetOutputSizePixel();
1789  const auto &rList = mpTabCtrlData->maItemList;
1790  const auto it = std::find_if(rList.begin(), rList.end(), [&rPos, &winSize, this](const auto &item) {
1791  return const_cast<TabControl*>(this)->ImplGetTabRect(&item, winSize.Width(), winSize.Height()).Contains(rPos); });
1792  return (it != rList.end()) ? it->id() : 0;
1793 }
1794 
1795 sal_uInt16 TabControl::GetPageId( const OString& rName ) const
1796 {
1797  const auto &rList = mpTabCtrlData->maItemList;
1798  const auto it = std::find_if(rList.begin(), rList.end(), [&rName](const auto &item) {
1799  return item.maTabName == rName; });
1800  return (it != rList.end()) ? it->id() : 0;
1801 }
1802 
1803 void TabControl::SetCurPageId( sal_uInt16 nPageId )
1804 {
1805  sal_uInt16 nPos = GetPagePos( nPageId );
1806  while (nPos != TAB_PAGE_NOTFOUND && !mpTabCtrlData->maItemList[nPos].m_bEnabled)
1807  {
1808  nPos++;
1809  if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1810  nPos = 0;
1811  if (mpTabCtrlData->maItemList[nPos].id() == nPageId)
1812  break;
1813  }
1814 
1815  if( nPos == TAB_PAGE_NOTFOUND )
1816  return;
1817 
1818  nPageId = mpTabCtrlData->maItemList[nPos].id();
1819  if ( nPageId == mnCurPageId )
1820  {
1821  if ( mnActPageId )
1822  mnActPageId = nPageId;
1823  return;
1824  }
1825 
1826  if ( mnActPageId )
1827  mnActPageId = nPageId;
1828  else
1829  {
1830  mbFormat = true;
1831  sal_uInt16 nOldId = mnCurPageId;
1832  mnCurPageId = nPageId;
1833  ImplChangeTabPage( nPageId, nOldId );
1834  }
1835 }
1836 
1837 sal_uInt16 TabControl::GetCurPageId() const
1838 {
1839  if ( mnActPageId )
1840  return mnActPageId;
1841  else
1842  return mnCurPageId;
1843 }
1844 
1845 void TabControl::SelectTabPage( sal_uInt16 nPageId )
1846 {
1847  if ( !nPageId || (nPageId == mnCurPageId) )
1848  return;
1849 
1851 
1852  CallEventListeners( VclEventId::TabpageDeactivate, reinterpret_cast<void*>(mnCurPageId) );
1853  if ( DeactivatePage() )
1854  {
1855  mnActPageId = nPageId;
1856  ActivatePage();
1857  // Page could have been switched by the Activate handler
1858  nPageId = mnActPageId;
1859  mnActPageId = 0;
1860  SetCurPageId( nPageId );
1861  if( mpTabCtrlData->mpListBox )
1862  mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1863  CallEventListeners( VclEventId::TabpageActivate, reinterpret_cast<void*>(nPageId) );
1864  }
1865 }
1866 
1867 void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1868 {
1869  ImplTabItem* pItem = ImplGetItem( nPageId );
1870 
1871  if ( !pItem || (pItem->mpTabPage.get() == pTabPage) )
1872  return;
1873 
1874  if ( pTabPage )
1875  {
1876  if ( IsDefaultSize() )
1877  SetTabPageSizePixel( pTabPage->GetSizePixel() );
1878 
1879  // only set here, so that Resize does not reposition TabPage
1880  pItem->mpTabPage = pTabPage;
1881  queue_resize();
1882 
1883  if (pItem->id() == mnCurPageId)
1884  ImplChangeTabPage(pItem->id(), 0);
1885  }
1886  else
1887  {
1888  pItem->mpTabPage = nullptr;
1889  queue_resize();
1890  }
1891 }
1892 
1893 TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1894 {
1895  ImplTabItem* pItem = ImplGetItem( nPageId );
1896 
1897  if ( pItem )
1898  return pItem->mpTabPage;
1899  else
1900  return nullptr;
1901 }
1902 
1903 void TabControl::SetPageText( sal_uInt16 nPageId, const OUString& rText )
1904 {
1905  ImplTabItem* pItem = ImplGetItem( nPageId );
1906 
1907  if ( !pItem || pItem->maText == rText )
1908  return;
1909 
1910  pItem->maText = rText;
1911  mbFormat = true;
1912  if( mpTabCtrlData->mpListBox )
1913  {
1914  sal_uInt16 nPos = GetPagePos( nPageId );
1915  mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1916  mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
1917  }
1918  if ( IsUpdateMode() )
1919  Invalidate();
1921  CallEventListeners( VclEventId::TabpagePageTextChanged, reinterpret_cast<void*>(nPageId) );
1922 }
1923 
1924 OUString const & TabControl::GetPageText( sal_uInt16 nPageId ) const
1925 {
1926  ImplTabItem* pItem = ImplGetItem( nPageId );
1927 
1928  assert( pItem );
1929 
1930  return pItem->maText;
1931 }
1932 
1933 void TabControl::SetHelpText( sal_uInt16 nPageId, const OUString& rText )
1934 {
1935  ImplTabItem* pItem = ImplGetItem( nPageId );
1936 
1937  assert( pItem );
1938 
1939  pItem->maHelpText = rText;
1940 }
1941 
1942 const OUString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
1943 {
1944  ImplTabItem* pItem = ImplGetItem( nPageId );
1945  assert( pItem );
1946  return pItem->maHelpText;
1947 }
1948 
1949 void TabControl::SetAccessibleName(sal_uInt16 nPageId, const OUString& rName)
1950 {
1951  ImplTabItem* pItem = ImplGetItem( nPageId );
1952  assert( pItem );
1953  pItem->maAccessibleName = rName;
1954 }
1955 
1956 OUString TabControl::GetAccessibleName( sal_uInt16 nPageId ) const
1957 {
1958  ImplTabItem* pItem = ImplGetItem( nPageId );
1959  assert( pItem );
1960  if (!pItem->maAccessibleName.isEmpty())
1961  return pItem->maAccessibleName;
1963 }
1964 
1965 void TabControl::SetAccessibleDescription(sal_uInt16 nPageId, const OUString& rDesc)
1966 {
1967  ImplTabItem* pItem = ImplGetItem( nPageId );
1968  assert( pItem );
1969  pItem->maAccessibleDescription = rDesc;
1970 }
1971 
1972 OUString TabControl::GetAccessibleDescription( sal_uInt16 nPageId ) const
1973 {
1974  ImplTabItem* pItem = ImplGetItem( nPageId );
1975  assert( pItem );
1976  if (!pItem->maAccessibleDescription.isEmpty())
1977  return pItem->maAccessibleDescription;
1978  return pItem->maHelpText;
1979 }
1980 
1981 void TabControl::SetPageName( sal_uInt16 nPageId, const OString& rName ) const
1982 {
1983  ImplTabItem* pItem = ImplGetItem( nPageId );
1984 
1985  if ( pItem )
1986  pItem->maTabName = rName;
1987 }
1988 
1989 OString TabControl::GetPageName( sal_uInt16 nPageId ) const
1990 {
1991  ImplTabItem* pItem = ImplGetItem( nPageId );
1992 
1993  if (pItem)
1994  return pItem->maTabName;
1995 
1996  return OString();
1997 }
1998 
1999 void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2000 {
2001  ImplTabItem* pItem = ImplGetItem( i_nPageId );
2002 
2003  if ( pItem )
2004  {
2005  pItem->maTabImage = i_rImage;
2006  mbFormat = true;
2007  if ( IsUpdateMode() )
2008  Invalidate();
2009  }
2010 }
2011 
2013 {
2014  tools::Rectangle aRet;
2015 
2016  if( !HasLayoutData() || mpTabCtrlData->maLayoutPageIdToLine.empty() )
2017  FillLayoutData();
2018 
2019  if( HasLayoutData() )
2020  {
2021  std::unordered_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( static_cast<int>(nPageId) );
2022  if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2023  {
2024  Pair aPair = mxLayoutData->GetLineStartEnd( it->second );
2025  if( (aPair.B() - aPair.A()) >= nIndex )
2026  aRet = mxLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2027  }
2028  }
2029 
2030  return aRet;
2031 }
2032 
2033 tools::Long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const
2034 {
2035  tools::Long nRet = -1;
2036 
2037  if( !HasLayoutData() || mpTabCtrlData->maLayoutPageIdToLine.empty() )
2038  FillLayoutData();
2039 
2040  if( HasLayoutData() )
2041  {
2042  int nIndex = mxLayoutData->GetIndexForPoint( rPoint );
2043  if( nIndex != -1 )
2044  {
2045  // what line (->pageid) is this index in ?
2046  int nLines = mxLayoutData->GetLineCount();
2047  int nLine = -1;
2048  while( ++nLine < nLines )
2049  {
2050  Pair aPair = mxLayoutData->GetLineStartEnd( nLine );
2051  if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2052  {
2053  nRet = nIndex - aPair.A();
2054  rPageId = static_cast<sal_uInt16>(mpTabCtrlData->maLayoutLineToPageId[ nLine ]);
2055  break;
2056  }
2057  }
2058  }
2059  }
2060 
2061  return nRet;
2062 }
2063 
2065 {
2066  mpTabCtrlData->maLayoutLineToPageId.clear();
2067  mpTabCtrlData->maLayoutPageIdToLine.clear();
2068  const_cast<TabControl*>(this)->Invalidate();
2069 }
2070 
2071 tools::Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const
2072 {
2073  tools::Rectangle aRet;
2074 
2075  ImplTabItem* pItem = ImplGetItem( nPageId );
2076  if (pItem && pItem->m_bVisible)
2077  aRet = pItem->maRect;
2078 
2079  return aRet;
2080 }
2081 
2082 Size TabControl::ImplCalculateRequisition(sal_uInt16& nHeaderHeight) const
2083 {
2084  Size aOptimalPageSize(0, 0);
2085 
2086  sal_uInt16 nOrigPageId = GetCurPageId();
2087  for (auto const& item : mpTabCtrlData->maItemList)
2088  {
2089  const TabPage *pPage = item.mpTabPage;
2090  //it's a real nuisance if the page is not inserted yet :-(
2091  //We need to force all tabs to exist to get overall optimal size for dialog
2092  if (!pPage)
2093  {
2094  TabControl *pThis = const_cast<TabControl*>(this);
2095  pThis->SetCurPageId(item.id());
2096  pThis->ActivatePage();
2097  pPage = item.mpTabPage;
2098  }
2099 
2100  if (!pPage)
2101  continue;
2102 
2103  Size aPageSize(VclContainer::getLayoutRequisition(*pPage));
2104 
2105  if (aPageSize.Width() > aOptimalPageSize.Width())
2106  aOptimalPageSize.setWidth( aPageSize.Width() );
2107  if (aPageSize.Height() > aOptimalPageSize.Height())
2108  aOptimalPageSize.setHeight( aPageSize.Height() );
2109  }
2110 
2111  //fdo#61940 If we were forced to activate pages in order to on-demand
2112  //create them to get their optimal size, then switch back to the original
2113  //page and re-activate it
2114  if (nOrigPageId != GetCurPageId())
2115  {
2116  TabControl *pThis = const_cast<TabControl*>(this);
2117  pThis->SetCurPageId(nOrigPageId);
2118  pThis->ActivatePage();
2119  }
2120 
2121  tools::Long nTabLabelsBottom = 0, nTabLabelsRight = 0;
2122  for (sal_uInt16 nPos(0), sizeList(static_cast <sal_uInt16> (mpTabCtrlData->maItemList.size()));
2123  nPos < sizeList; ++nPos)
2124  {
2125  TabControl* pThis = const_cast<TabControl*>(this);
2126 
2127  tools::Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aOptimalPageSize.Width(), LONG_MAX);
2128  if (aTabRect.Bottom() > nTabLabelsBottom)
2129  {
2130  nTabLabelsBottom = aTabRect.Bottom();
2131  nHeaderHeight = nTabLabelsBottom;
2132  }
2133  if (!aTabRect.IsEmpty() && aTabRect.Right() > nTabLabelsRight)
2134  nTabLabelsRight = aTabRect.Right();
2135  }
2136 
2137  Size aOptimalSize(aOptimalPageSize);
2138  aOptimalSize.AdjustHeight(nTabLabelsBottom );
2139  aOptimalSize.setWidth( std::max(nTabLabelsRight, aOptimalSize.Width()) );
2140 
2141  aOptimalSize.AdjustWidth(TAB_OFFSET * 2 );
2142  aOptimalSize.AdjustHeight(TAB_OFFSET * 2 );
2143 
2144  return aOptimalSize;
2145 }
2146 
2148 {
2149  sal_uInt16 nHeaderHeight;
2150  return ImplCalculateRequisition(nHeaderHeight);
2151 }
2152 
2154 {
2155  return calculateRequisition();
2156 }
2157 
2159 {
2160  mbLayoutDirty = true;
2161  Window::queue_resize(eReason);
2162 }
2163 
2164 std::vector<sal_uInt16> TabControl::GetPageIDs() const
2165 {
2166  std::vector<sal_uInt16> aIDs;
2167  for (auto const& item : mpTabCtrlData->maItemList)
2168  {
2169  aIDs.push_back(item.id());
2170  }
2171 
2172  return aIDs;
2173 }
2174 
2176 {
2178 }
2179 
2181 {
2182  rJsonWriter.put("id", get_id());
2183  rJsonWriter.put("type", "tabcontrol");
2184  rJsonWriter.put("selected", GetCurPageId());
2185 
2186  {
2187  auto childrenNode = rJsonWriter.startArray("children");
2188  for (int i = 0; i < GetChildCount(); i++)
2189  {
2190  vcl::Window* pChild = GetChild(i);
2191 
2192  if (pChild)
2193  {
2194  auto childNode = rJsonWriter.startStruct();
2195  pChild->DumpAsPropertyTree(rJsonWriter);
2196 
2197  if (!pChild->IsVisible())
2198  rJsonWriter.put("hidden", "true");
2199  }
2200  }
2201  }
2202  {
2203  auto tabsNode = rJsonWriter.startArray("tabs");
2204  for(auto id : GetPageIDs())
2205  {
2206  auto tabNode = rJsonWriter.startStruct();
2207  rJsonWriter.put("text", GetPageText(id));
2208  rJsonWriter.put("id", id);
2209  rJsonWriter.put("name", GetPageName(id));
2210  }
2211  }
2212 }
2213 
2214 sal_uInt16 NotebookbarTabControlBase::m_nHeaderHeight = 0;
2215 
2216 IMPL_LINK_NOARG(NotebookbarTabControlBase, OpenMenu, Button*, void)
2217 {
2218  m_aIconClickHdl.Call(static_cast<NotebookBar*>(GetParent()->GetParent()));
2219 }
2220 
2221 NotebookbarTabControlBase::NotebookbarTabControlBase(vcl::Window* pParent)
2222  : TabControl(pParent, WB_STDTABCONTROL)
2223  , bLastContextWasSupported(true)
2224  , eLastContext(vcl::EnumContext::Context::Any)
2225 {
2226  m_pOpenMenu = VclPtr<PushButton>::Create( this , WB_CENTER | WB_VCENTER );
2227  m_pOpenMenu->SetClickHdl(LINK(this, NotebookbarTabControlBase, OpenMenu));
2228  m_pOpenMenu->SetModeImage(Image(StockImage::Yes, SV_RESID_BITMAP_NOTEBOOKBAR));
2229  m_pOpenMenu->SetSizePixel(m_pOpenMenu->GetOptimalSize());
2230  m_pOpenMenu->Show();
2231 }
2232 
2233 NotebookbarTabControlBase::~NotebookbarTabControlBase()
2234 {
2235  disposeOnce();
2236 }
2237 
2238 void NotebookbarTabControlBase::SetContext( vcl::EnumContext::Context eContext )
2239 {
2240  if (eLastContext == eContext)
2241  return;
2242 
2243  bool bHandled = false;
2244 
2245  for (int nChild = 0; nChild < GetPageCount(); ++nChild)
2246  {
2247  sal_uInt16 nPageId = TabControl::GetPageId(nChild);
2248  TabPage* pPage = GetTabPage(nPageId);
2249 
2250  if (pPage)
2251  {
2252  SetPageVisible(nPageId, pPage->HasContext(eContext) || pPage->HasContext(vcl::EnumContext::Context::Any));
2253 
2254  if (!bHandled && bLastContextWasSupported
2256  {
2257  SetCurPageId(nPageId);
2258  }
2259 
2260  if (pPage->HasContext(eContext) && eContext != vcl::EnumContext::Context::Any)
2261  {
2262  SetCurPageId(nPageId);
2263  bHandled = true;
2264  bLastContextWasSupported = true;
2265  }
2266  }
2267  }
2268 
2269  if (!bHandled)
2270  bLastContextWasSupported = false;
2271  eLastContext = eContext;
2272 }
2273 
2274 void NotebookbarTabControlBase::dispose()
2275 {
2276  m_pShortcuts.disposeAndClear();
2277  m_pOpenMenu.disposeAndClear();
2279 }
2280 
2281 void NotebookbarTabControlBase::SetToolBox( ToolBox* pToolBox )
2282 {
2283  m_pShortcuts.set( pToolBox );
2284 }
2285 
2286 void NotebookbarTabControlBase::SetIconClickHdl( Link<NotebookBar*, void> aHdl )
2287 {
2288  m_aIconClickHdl = aHdl;
2289 }
2290 
2291 static bool lcl_isValidPage(const ImplTabItem& rItem, bool& bFound)
2292 {
2293  if (rItem.m_bVisible && rItem.m_bEnabled)
2294  bFound = true;
2295  return bFound;
2296 }
2297 
2298 void NotebookbarTabControlBase::ImplActivateTabPage( bool bNext )
2299 {
2300  const sal_uInt16 nOldPos = GetPagePos(GetCurPageId());
2301  bool bFound = false;
2302  sal_Int32 nCurPos = nOldPos;
2303 
2304  if (bNext)
2305  {
2306  for (nCurPos++; nCurPos < GetPageCount(); nCurPos++)
2307  if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2308  break;
2309  }
2310  else
2311  {
2312  for (nCurPos--; nCurPos >= 0; nCurPos--)
2313  if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2314  break;
2315  }
2316 
2317  if (!bFound)
2318  nCurPos = nOldPos;
2319  SelectTabPage( TabControl::GetPageId( nCurPos ) );
2320 }
2321 
2322 sal_uInt16 NotebookbarTabControlBase::GetHeaderHeight()
2323 {
2324  return m_nHeaderHeight;
2325 }
2326 
2327 bool NotebookbarTabControlBase::ImplPlaceTabs( tools::Long nWidth )
2328 {
2329  if ( nWidth <= 0 )
2330  return false;
2331  if ( mpTabCtrlData->maItemList.empty() )
2332  return false;
2333  if (!m_pOpenMenu || m_pOpenMenu->isDisposed())
2334  return false;
2335 
2336  const tools::Long nHamburgerWidth = m_pOpenMenu->GetSizePixel().Width();
2337  tools::Long nMaxWidth = nWidth - nHamburgerWidth;
2338  tools::Long nShortcutsWidth = m_pShortcuts != nullptr ? m_pShortcuts->GetSizePixel().getWidth() + 1 : 0;
2339  tools::Long nFullWidth = nShortcutsWidth;
2340 
2341  const tools::Long nOffsetX = 2 + nShortcutsWidth;
2342  const tools::Long nOffsetY = 2;
2343 
2344  //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
2345  //of ugly bare tabs on lines of their own
2346 
2347  for (auto & item : mpTabCtrlData->maItemList)
2348  {
2349  tools::Long nTabWidth = 0;
2350  if (item.m_bVisible)
2351  {
2352  nTabWidth = ImplGetItemSize(&item, nMaxWidth).getWidth();
2353  if (!item.maText.isEmpty() && nTabWidth < 100)
2354  nTabWidth = 100;
2355  }
2356  nFullWidth += nTabWidth;
2357  }
2358 
2359  tools::Long nX = nOffsetX;
2360  tools::Long nY = nOffsetY;
2361 
2362  tools::Long nLineWidthAry[100];
2363  nLineWidthAry[0] = 0;
2364 
2365  for (auto & item : mpTabCtrlData->maItemList)
2366  {
2367  if (!item.m_bVisible)
2368  continue;
2369 
2370  Size aSize = ImplGetItemSize( &item, nMaxWidth );
2371 
2372  // set minimum tab size
2373  if( nFullWidth < nMaxWidth && !item.maText.isEmpty() && aSize.getWidth() < 100)
2374  aSize.setWidth( 100 );
2375 
2376  if( !item.maText.isEmpty() && aSize.getHeight() < 28 )
2377  aSize.setHeight( 28 );
2378 
2379  tools::Rectangle aNewRect( Point( nX, nY ), aSize );
2380  if ( mbSmallInvalidate && (item.maRect != aNewRect) )
2381  mbSmallInvalidate = false;
2382 
2383  item.maRect = aNewRect;
2384  item.mnLine = 0;
2385  item.mbFullVisible = true;
2386 
2387  nLineWidthAry[0] += aSize.Width();
2388  nX += aSize.Width();
2389  }
2390 
2391  // we always have only one line of tabs
2392  lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
2393 
2394  // position the shortcutbox
2395  if (m_pShortcuts)
2396  {
2397  tools::Long nPosY = (m_nHeaderHeight - m_pShortcuts->GetSizePixel().getHeight()) / 2;
2398  m_pShortcuts->SetPosPixel(Point(0, nPosY));
2399  }
2400 
2401  tools::Long nPosY = (m_nHeaderHeight - m_pOpenMenu->GetSizePixel().getHeight()) / 2;
2402  // position the menu
2403  m_pOpenMenu->SetPosPixel(Point(nWidth - nHamburgerWidth, nPosY));
2404 
2405  return true;
2406 }
2407 
2408 Size NotebookbarTabControlBase::calculateRequisition() const
2409 {
2410  return TabControl::ImplCalculateRequisition(m_nHeaderHeight);
2411 }
2412 
2413 Control* NotebookbarTabControlBase::GetOpenMenu()
2414 {
2415  return m_pOpenMenu;
2416 }
2417 
2418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: window3.cxx:65
virtual const vcl::Font & GetCanonicalFont(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:132
Size GetSizePixel() const
Definition: Image.cxx:86
const Color & GetTextColor() const
Definition: outdev.hxx:1016
const Color & GetShadowColor() const
bool IsControlBackground() const
Definition: window2.cxx:1110
virtual void queue_resize(StateChangedType eReason=StateChangedType::Layout) override
Definition: tabctrl.cxx:2158
void SetBackground()
Definition: window3.cxx:100
Point GetPointerPosPixel()
Definition: mouse.cxx:564
sal_uInt16 m_nId
Definition: tabctrl.cxx:48
void HideFocus()
Definition: window2.cxx:94
sal_Int32 nIndex
const Color & GetDialogColor() const
virtual void Command(const CommandEvent &rCEvt) override
Definition: tabctrl.cxx:1435
virtual void RequestHelp(const HelpEvent &rHEvt) override
Definition: tabctrl.cxx:1365
bool mbLayoutDirty
Definition: tabctrl.hxx:62
SAL_DLLPRIVATE bool ImplHandleKeyEvent(const KeyEvent &rKeyEvent)
Definition: tabctrl.cxx:989
bool mbSmallInvalidate
Definition: tabctrl.hxx:61
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
This is an overloaded member function, provided for convenience. It differs from the above function o...
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long mnLastWidth
Definition: tabctrl.hxx:55
void setWidth(tools::Long nWidth)
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
virtual void SetPosPixel(const Point &rPos) override
Definition: tabctrl.cxx:1331
VclPtr< TabPage > mpTabPage
Definition: tabctrl.cxx:51
SAL_DLLPRIVATE void ImplDrawItem(vcl::RenderContext &rRenderContext, ImplTabItem const *pItem, const tools::Rectangle &rCurRect, bool bFirstInGroup, bool bLastInGroup)
Definition: tabctrl.cxx:797
ScopedJsonWriterStruct startStruct()
SAL_DLLPRIVATE void ImplFreeLayoutData()
Definition: tabctrl.cxx:177
virtual const Color & GetCanonicalTextColor(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:137
bool mbNoActiveTabTextRaise
Definition: svdata.hxx:331
std::optional< vcl::ControlLayoutData > mxLayoutData
Definition: ctrl.hxx:84
void SetHelpId(sal_uInt16 nItemId, const OString &rHelpId)
Definition: menu.cxx:1120
A widget used to choose from a list of items and which has no entry.
Definition: lstbox.hxx:82
WinBits const WB_NODIALOGCONTROL
constexpr tools::Long Left() const
bool Contains(const Point &rPOINT) const
WinBits const WB_NOGROUP
void Union(const tools::Rectangle &rRegion)
Definition: region.cxx:506
SAL_DLLPRIVATE void ImplClearLayoutData() const
Definition: ctrl.cxx:326
void SelectTabPage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1845
static Size getLayoutRequisition(const vcl::Window &rWindow)
Definition: layout.cxx:151
long Long
tools::Long mnLastHeight
Definition: tabctrl.hxx:56
const StyleSettings & GetStyleSettings() const
sal_uInt16 mnActPageId
Definition: tabctrl.hxx:57
static std::deque< size_t > GetEndOfLineIndexes(const std::vector< sal_Int32 > &rWidthsOf, sal_Int32 nLineWidth)
Definition: tabctrl.cxx:296
ScopedJsonWriterArray startArray(const char *)
const OUString & GetHelpText() const
Definition: window.cxx:3096
virtual void StateChanged(StateChangedType nStateChange) override
Definition: ctrl.cxx:256
ImplSVNWFData maNWFData
Definition: svdata.hxx:404
sal_Int64 n
Link< TabControl *, bool > maDeactivateHdl
Definition: tabctrl.hxx:64
void SetPageVisible(sal_uInt16 nPageId, bool bVisible=true)
Definition: tabctrl.cxx:1738
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual Size GetSizePixel() const
Definition: window.cxx:2405
SAL_DLLPRIVATE WindowImpl * ImplGetWindowImpl() const
Definition: window.hxx:527
OUString const & GetPageText(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1924
sal_Int16 nId
TabPage * GetTabPage(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1893
ImplTabItem(sal_uInt16 nId)
Definition: tabctrl.cxx:70
void SetPageEnabled(sal_uInt16 nPageId, bool bEnable=true)
Definition: tabctrl.cxx:1715
#define TAB_BORDER_RIGHT
Definition: tabctrl.hxx:48
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
std::unordered_map< int, int > maLayoutPageIdToLine
Definition: tabctrl.cxx:81
void RemoveChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:324
OUString GetAccessibleDescription() const
DataChangedEventType GetType() const
Definition: event.hxx:362
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
sal_uInt16 Execute(vcl::Window *pWindow, const Point &rPopupPos)
Definition: menu.cxx:2743
std::unique_ptr< ImplTabCtrlData > mpTabCtrlData
Definition: tabctrl.hxx:54
void SetHelpId(const OString &)
Definition: window2.cxx:841
tools::Rectangle DrawControlText(OutputDevice &_rTargetDevice, const tools::Rectangle &_rRect, const OUString &_rStr, DrawTextFlags _nStyle, std::vector< tools::Rectangle > *_pVector, OUString *_pDisplayText, const Size *i_pDeviceSize=nullptr) const
draws the given text onto the given device
Definition: ctrl.cxx:428
const Color & GetControlBackground() const
Definition: window2.cxx:1105
virtual Size calculateRequisition() const
Definition: tabctrl.cxx:2147
bool HasChildPathFocus(bool bSystemWindow=false) const
Definition: window.cxx:3010
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
DrawTextFlags
HelpEventMode GetMode() const
Definition: event.hxx:208
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1538
virtual Size GetOptimalSize() const override
Definition: tabctrl.cxx:2153
OUString maText
Definition: tabctrl.cxx:52
StateChangedType
Definition: window.hxx:289
constexpr tools::Long Width() const
SAL_DLLPRIVATE ImplTabItem * ImplGetItem(sal_uInt16 nId) const
Definition: tabctrl.cxx:214
void SetAccessibleName(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1949
OUString GetAccessibleName() const
A construction helper for ScopedVclPtr.
Definition: vclptr.hxx:407
sal_Int64 WinBits
OString GetPageName(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1989
const OUString & get_id() const
Get the ID of the window.
Definition: window.cxx:3935
sal_uInt16 nPageId
OUString maFormatText
Definition: tabctrl.cxx:53
sal_uInt16 GetButtons() const
Definition: event.hxx:147
virtual void LoseFocus() override
Definition: tabctrl.cxx:1358
this flags lets the item be drawn disabled (e.g.
virtual void DumpAsPropertyTree(tools::JsonWriter &)
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: window.cxx:3364
virtual void SetCurPageId(const OString &rName) override
void SetPageImage(sal_uInt16 nPageId, const Image &rImage)
Definition: tabctrl.cxx:1999
const vcl::Font & GetFont() const
Definition: outdev.hxx:540
bool IsEnterWindow() const
Definition: event.hxx:138
bool mbFullVisible
Definition: tabctrl.cxx:60
bool IsMouseEvent() const
tools::Long GetIndexForPoint(const Point &rPoint, sal_uInt16 &rPageId) const
Definition: tabctrl.cxx:2033
bool IsDefaultSize() const
Definition: window2.cxx:1176
constexpr Point BottomLeft() const
void Hide()
Definition: window.hxx:884
virtual FactoryFunction GetUITestFactory() const override
Definition: tabctrl.cxx:2175
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1587
const Color & GetLightColor() const
TabitemFlags mnAlignment
virtual void GetFocus() override
Definition: tabctrl.cxx:1343
static bool lcl_isValidPage(const ImplTabItem &rItem, bool &bFound)
Definition: tabctrl.cxx:2291
tools::Long GetCtrlTextWidth(const OUString &rStr, const SalLayoutGlyphs *pLayoutCache=nullptr) const
Definition: text.cxx:2325
bool mbRestoreHelpId
Definition: tabctrl.hxx:60
static bool lcl_canPaint(const vcl::RenderContext &rRenderContext, const tools::Rectangle &rDrawRect, const tools::Rectangle &rItemRect)
Definition: tabctrl.cxx:1069
tools::Rectangle GetCharacterBounds(sal_uInt16 nPageId, tools::Long nIndex) const
Definition: tabctrl.cxx:2012
constexpr tools::Long getHeight() const
void SetCurPageId(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1803
virtual void KeyInput(const KeyEvent &rKEvt) override
Definition: tabctrl.cxx:1050
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
Definition: line.cxx:160
OUString maHelpText
Definition: tabctrl.cxx:54
SAL_DLLPRIVATE void ImplControlFocus(GetFocusFlags nFlags=GetFocusFlags::NONE)
Definition: dlgctrl.cxx:516
virtual void StateChanged(StateChangedType nType) override
Definition: tabctrl.cxx:1473
sal_uInt16 mnCurPageId
Definition: tabctrl.hxx:58
sal_uInt16 GetPageCount() const
Definition: tabctrl.cxx:1761
bool IsChildTransparentModeEnabled() const
Definition: window2.cxx:1050
SAL_DLLPRIVATE vcl::Window * ImplGetDlgWindow(sal_uInt16 n, GetDlgWindowType nType, sal_uInt16 nStart=0, sal_uInt16 nEnd=0xFFFF, sal_uInt16 *pIndex=nullptr)
Definition: dlgctrl.cxx:205
constexpr bool IsEmpty() const
this flag disables a selection of an entry completely.
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
Definition: tabctrl.cxx:1315
constexpr void SetLeft(tools::Long v)
const Point & GetMousePosPixel() const
Definition: event.hxx:207
#define TAB_BORDER_BOTTOM
Definition: tabctrl.hxx:49
const Color & GetDarkShadowColor() const
WinBits const WB_DIALOGCONTROL
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
bool IsEmpty() const
Definition: region.cxx:229
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: tabctrl.cxx:1079
void SetLineColor()
Definition: line.cxx:36
const OString & GetHelpId() const
Definition: window2.cxx:846
void SetAccessibleDescription(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1965
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: tabctrl.cxx:90
#define SAL_MAX_INT32
Point LogicToPixel(const Point &rLogicPt) const
Definition: window3.cxx:131
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:52
Window(WindowType nType)
Definition: window.cxx:95
void SetInputContext(const InputContext &rInputContext)
Definition: window.cxx:2079
bool IsLeaveWindow() const
Definition: event.hxx:140
int i
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: tabctrl.cxx:1506
SAL_DLLPRIVATE tools::Rectangle ImplGetTabRect(sal_uInt16 nPos, tools::Long nWidth=-1, tools::Long nHeight=-1)
Definition: tabctrl.cxx:550
void SetPageText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1903
virtual bool ImplPlaceTabs(tools::Long nWidth)
Definition: tabctrl.cxx:392
A toolbar: contains all those icons, typically below the menu bar.
Definition: toolbox.hxx:75
OUString maAccessibleDescription
Definition: tabctrl.cxx:56
Link< TabControl *, void > maActivateHdl
Definition: tabctrl.hxx:63
const vcl::Font & GetTabFont() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
Definition: paint.cxx:1143
SAL_DLLPRIVATE void ImplShowFocus()
Definition: tabctrl.cxx:747
void CallEventListeners(VclEventId nEvent, void *pData=nullptr)
Definition: ctrl.cxx:293
OUString maAccessibleName
Definition: tabctrl.cxx:55
bool IsUpdateMode() const
Definition: window2.cxx:1196
constexpr tools::Long Right() const
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:175
virtual void DumpAsPropertyTree(tools::JsonWriter &) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: tabctrl.cxx:2180
const AllSettings & GetSettings() const
Definition: window3.cxx:129
CommandEventId GetCommand() const
bool HasContext(const vcl::EnumContext::Context eContext) const
Definition: IContext.hxx:30
float u
bool IsDialog() const
Definition: window2.cxx:1025
void SetTextColor(const Color &rColor)
Definition: text.cxx:714
bool GetNativeControlRegion(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion) const
Query the native control's actual drawing region (including adornment)
Definition: window3.cxx:79
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
constexpr tools::Long Top() const
void Intersect(const tools::Rectangle &rRegion)
Definition: region.cxx:582
MouseNotifyEvent GetType() const
Definition: event.hxx:308
SAL_DLLPRIVATE void ImplChangeTabPage(sal_uInt16 nId, sal_uInt16 nOldId)
Definition: tabctrl.cxx:616
bool DrawNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, const OUString &aCaption, const Color &rBackgroundColor=COL_AUTO)
Request rendering of a particular control and/or part.
constexpr void SetRight(tools::Long v)
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: ctrl.cxx:58
WinBits const WB_DROPDOWN
const AllSettings & GetSettings() const
Definition: outdev.hxx:295
void SetPaintTransparent(bool bTransparent)
Definition: paint.cxx:1025
constexpr void SetBottom(tools::Long v)
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
Definition: tabpage.cxx:198
std::vector< ImplTabItem > maItemList
Definition: tabctrl.cxx:83
virtual void LoseFocus()
Definition: window.cxx:1858
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2815
#define TAB_TABOFFSET_Y
Definition: tabctrl.hxx:44
bool KeyboardActivated() const
Definition: event.hxx:209
void GrabFocus()
Definition: window.cxx:2982
Image maTabImage
Definition: tabctrl.cxx:63
static void ShowQuickHelp(vcl::Window *pParent, const tools::Rectangle &rScreenRect, const OUString &rHelpText, QuickHelpFlags nStyle=QuickHelpFlags::NONE)
Definition: help.cxx:180
void SetTabPageSizePixel(const Size &rSize)
Definition: tabctrl.cxx:1607
virtual void ShowFocus(const tools::Rectangle &rRect)
Definition: window2.cxx:52
vcl::Window * GetParent() const
Definition: window2.cxx:1120
void DrawPixel(const Point &rPt)
Definition: pixel.cxx:56
bool IsReallyShown() const
Definition: window2.cxx:1135
constexpr void SetTop(tools::Long v)
SAL_DLLPRIVATE bool ImplPosCurTabPage()
Definition: tabctrl.cxx:710
const long LONG_MAX
virtual void Resize() override
Definition: tabctrl.cxx:1338
void put(const char *pPropName, const OUString &rPropValue)
sal_uInt16 GetPagePos(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1773
sal_uInt16 id() const
Definition: tabctrl.cxx:67
WinBits const WB_NOBORDER
void CheckItem(sal_uInt16 nItemId, bool bCheck=true)
Definition: menu.cxx:813
constexpr Point Center() const
constexpr Point TopLeft() const
const sal_uInt16 idx[]
StyleSettingsOptions GetOptions() const
sal_uInt16 mnLine
Definition: tabctrl.cxx:59
tools::Long AdjustTop(tools::Long nVertMoveDelta)
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
bool mbFormat
Definition: tabctrl.hxx:59
const Point & GetMousePosPixel() const
constexpr tools::Long Bottom() const
VclPtr< ListBox > mpListBox
Definition: tabctrl.cxx:84
std::vector< sal_uInt16 > GetPageIDs() const
Definition: tabctrl.cxx:2164
virtual void KeyInput(const KeyEvent &rKEvt)
Definition: window.cxx:1808
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle, SystemParentData *pSystemParentData)
Definition: window.cxx:941
bool mbUseNativeFocus
Definition: window.h:317
SAL_DLLPRIVATE Size ImplGetItemSize(ImplTabItem *pItem, tools::Long nMaxWidth)
Definition: tabctrl.cxx:225
bool IsModifierChanged() const
Definition: event.hxx:144
void SetPageName(sal_uInt16 nPageId, const OString &rName) const
Definition: tabctrl.cxx:1981
tools::Long A() const
#define TAB_PAGE_NOTFOUND
Definition: tabctrl.hxx:39
void InsertItem(sal_uInt16 nItemId, const OUString &rStr, MenuItemBits nItemBits=MenuItemBits::NONE, const OString &rIdent=OString(), sal_uInt16 nPos=MENU_APPEND)
Definition: menu.cxx:432
#define TAB_BORDER_LEFT
Definition: tabctrl.hxx:46
sal_uInt16 GetChildCount() const
Definition: stacking.cxx:1001
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
tools::Rectangle maRect
Definition: tabctrl.cxx:58
constexpr Size GetSize() const
bool IsShift() const
Definition: keycod.hxx:54
virtual ~TabControl() override
Definition: tabctrl.cxx:194
void setAllocation(const Size &rAllocation)
Definition: tabctrl.cxx:1253
bool IsMouseOver() const
Definition: mouse.cxx:620
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: tabctrl.cxx:199
WindowType
Definition: ctrl.hxx:81
OString maTabName
Definition: tabctrl.cxx:57
bool IsSynthetic() const
Definition: event.hxx:142
virtual void GetFocus()
Definition: window.cxx:1844
bool mbNoFocusRects
Definition: svdata.hxx:328
#define SAL_WARN_IF(condition, area, stream)
IMPL_LINK(TabControl, ImplWindowEventListener, VclWindowEvent &, rEvent, void)
Definition: tabctrl.cxx:1027
constexpr tools::Long Height() const
SAL_DLLPRIVATE Size ImplCalculateRequisition(sal_uInt16 &nHeaderHeight) const
Definition: tabctrl.cxx:2082
virtual void FillLayoutData() const override
Definition: tabctrl.cxx:2064
void SetFont(const vcl::Font &rNewFont)
Definition: outdev/font.cxx:53
tools::Rectangle GetTabBounds(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:2071
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: tabctrl.cxx:1040
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:324
void SetTransparent(bool bTransparent)
Definition: font/font.cxx:124
virtual vcl::Region GetActiveClipRegion() const
bool IsVisible() const
Definition: window2.cxx:1125
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: text.cxx:895
#define SAL_INFO(area, stream)
constexpr Point TopRight() const
::OutputDevice const * GetOutDev() const
Definition: window.cxx:568
if(aStr!=aBuf) UpdateName_Impl(m_xFollowLb.get()
void EnableChildTransparentMode(bool bEnable=true)
Definition: window2.cxx:1045
bool IsLeft() const
Definition: event.hxx:149
virtual void ImplActivateTabPage(bool bNext)
Definition: tabctrl.cxx:730
sal_uInt16 GetPageId(sal_uInt16 nPos) const
Definition: tabctrl.cxx:1766
const Color & GetTabHighlightTextColor() const
tools::Long AdjustWidth(tools::Long n)
Definition: image.hxx:39
bool IsMod1() const
Definition: keycod.hxx:56
static VclPtr< reference_type > Create(Arg &&...arg)
A construction helper for VclPtr.
Definition: vclptr.hxx:127
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect)
Definition: paint.cxx:1020
static int m_nOverlap
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
void RemovePage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1669
const vcl::Font & GetFont() const
Definition: window3.cxx:58
const Point & GetPosPixel() const
Definition: event.hxx:123
std::unordered_map< int, int > maLayoutLineToPageId
Definition: tabctrl.cxx:82
tools::Long AdjustHeight(tools::Long n)
IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl, ListBox &, void)
Definition: tabctrl.cxx:1022
WinBits const WB_TABSTOP
#define TAB_TABOFFSET_X
Definition: tabctrl.hxx:43
Size GetOutputSizePixel() const
Definition: window3.cxx:89
#define TAB_BORDER_TOP
Definition: tabctrl.hxx:47
constexpr Point BottomRight() const
void setHeight(tools::Long nHeight)
void ImplInitSettings()
Definition: ctrl.cxx:423
static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
Definition: tabctrl.cxx:369
void SetTabPage(sal_uInt16 nPageId, TabPage *pPage)
Definition: tabctrl.cxx:1867
tools::Long B() const
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
bool IsEnabled() const
Definition: window2.cxx:1145
bool m_bVisible
the tab / page can be visible
Definition: tabctrl.cxx:62
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
const Color & GetTabRolloverTextColor() const
#define TAB_OFFSET
Definition: tabctrl.hxx:42
bool m_bEnabled
the tab / page is selectable
Definition: tabctrl.cxx:61
WinBits GetStyle() const
Definition: window2.cxx:976
void SetFont(const vcl::Font &rNewFont)
Definition: window3.cxx:59
constexpr tools::Long getWidth() const
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
Point OutputToScreenPixel(const Point &rPos) const
Definition: window.cxx:2809
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
Definition: window3.cxx:74
WinBits const WB_GROUP
Point GetLastPointerPosPixel()
Definition: mouse.cxx:576
#define TAB_PAGERECT
Definition: tabctrl.cxx:88
TabControl(vcl::Window *pParent, WinBits nStyle=WB_STDTABCONTROL)
Definition: tabctrl.cxx:187
virtual void Command(const CommandEvent &rCEvt)
Definition: window.cxx:1926
bool IsReallyVisible() const
Definition: window2.cxx:1130
static OUString GetNonMnemonicString(const OUString &rStr, sal_Int32 &rMnemonicPos)
Definition: text.cxx:2342
void InsertPage(sal_uInt16 nPageId, const OUString &rText, sal_uInt16 nPos=TAB_APPEND)
Definition: tabctrl.cxx:1619
WinBits const WB_STDTABCONTROL
const Wallpaper & GetBackground() const
Definition: window3.cxx:63
bool HasFocus() const
Definition: window.cxx:2987
virtual void RequestHelp(const HelpEvent &rHEvt)
Definition: window.cxx:1872
The child windows are not invalidated.
sal_Int32 nState
const Color & GetTabTextColor() const
WinBits const WB_NOTABSTOP
#define TAB_EXTRASPACE_X
Definition: tabctrl.hxx:45
aStr
void ActivatePage()
Definition: tabctrl.cxx:1597
void SetHelpText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1933
void AddChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:319
bool HasLayoutData() const
determines whether we currently have layout data
Definition: ctrl.cxx:90
sal_uInt16 nPos
sal_uInt16 GetCurPageId() const
Definition: tabctrl.cxx:1837
constexpr sal_uInt16 KEY_TAB
Definition: keycodes.hxx:121
virtual void DataChanged(const DataChangedEvent &rDCEvt)
Definition: event.cxx:36
static void ShowBalloon(vcl::Window *pParent, const Point &rScreenPos, const tools::Rectangle &, const OUString &rHelpText)
Definition: help.cxx:157
bool m_bDetectedRangeSegmentation false
constexpr tools::Long GetHeight() const
vcl::Window * GetChild(sal_uInt16 nChild) const
Definition: stacking.cxx:1017
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: ctrl.cxx:225
#define TAB_APPEND
Definition: tabctrl.hxx:38
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Definition: window.cxx:2190
bool DeactivatePage()
Definition: tabctrl.cxx:1602
virtual void SetSizePixel(const Size &rNewSize) override
Definition: tabctrl.cxx:1323