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