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