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/toolkit/button.hxx>
29 #include <vcl/tabpage.hxx>
30 #include <vcl/tabctrl.hxx>
32 #include <vcl/layout.hxx>
33 #include <vcl/toolkit/lstbox.hxx>
34 #include <vcl/settings.hxx>
35 #include <vcl/uitest/uiobject.hxx>
36 #include <bitmaps.hlst>
37 #include <tools/json_writer.hxx>
38 
39 #include <controldata.hxx>
40 #include <svdata.hxx>
41 #include <window.h>
42 
43 #include <deque>
44 #include <unordered_map>
45 #include <vector>
46 
47 class ImplTabItem final
48 {
49  sal_uInt16 m_nId;
50 
51 public:
53  OUString maText;
54  OUString maFormatText;
55  OUString maHelpText;
56  OUString maAccessibleName;
58  OString maTabName;
60  sal_uInt16 mnLine;
62  bool m_bEnabled;
63  bool m_bVisible;
65 
66  ImplTabItem(sal_uInt16 nId);
67 
68  sal_uInt16 id() const { return m_nId; }
69 };
70 
71 ImplTabItem::ImplTabItem(sal_uInt16 nId)
72  : m_nId(nId)
73  , mnLine(0)
74  , mbFullVisible(false)
75  , m_bEnabled(true)
76  , m_bVisible(true)
77 {
78 }
79 
81 {
82  std::unordered_map< int, int > maLayoutPageIdToLine;
83  std::unordered_map< int, int > maLayoutLineToPageId;
84  Point maItemsOffset; // offset of the tabitems
85  std::vector< ImplTabItem > maItemList;
87 };
88 
89 // for the Tab positions
90 #define TAB_PAGERECT 0xFFFF
91 
92 void TabControl::ImplInit( vcl::Window* pParent, WinBits nStyle )
93 {
94  mbLayoutDirty = true;
95 
96  if ( !(nStyle & WB_NOTABSTOP) )
97  nStyle |= WB_TABSTOP;
98  if ( !(nStyle & WB_NOGROUP) )
99  nStyle |= WB_GROUP;
100  if ( !(nStyle & WB_NODIALOGCONTROL) )
101  nStyle |= WB_DIALOGCONTROL;
102 
103  Control::ImplInit( pParent, nStyle, nullptr );
104 
105  mnLastWidth = 0;
106  mnLastHeight = 0;
107  mnActPageId = 0;
108  mnCurPageId = 0;
109  mbFormat = true;
110  mbRestoreHelpId = false;
111  mbSmallInvalidate = false;
112  mpTabCtrlData.reset(new ImplTabCtrlData);
113  mpTabCtrlData->mpListBox = nullptr;
114 
115  ImplInitSettings( true );
116 
117  if( nStyle & WB_DROPDOWN )
118  {
119  mpTabCtrlData->mpListBox = VclPtr<ListBox>::Create( this, WB_DROPDOWN );
120  mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
121  mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
122  mpTabCtrlData->mpListBox->Show();
123  }
124 
125  // if the tabcontrol is drawn (ie filled) by a native widget, make sure all controls will have transparent background
126  // otherwise they will paint with a wrong background
129 
130  if (pParent && pParent->IsDialog())
131  pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
132 }
133 
135 {
136  return _rStyle.GetTabFont();
137 }
138 
140 {
141  return _rStyle.GetTabTextColor();
142 }
143 
144 void TabControl::ImplInitSettings( bool bBackground )
145 {
147 
148  if ( !bBackground )
149  return;
150 
151  vcl::Window* pParent = GetParent();
152  if ( !IsControlBackground() &&
156 
157  {
158  // set transparent mode for NWF tabcontrols to have
159  // the background always cleared properly
162  SetPaintTransparent( true );
163  SetBackground();
165  }
166  else
167  {
170  SetPaintTransparent( false );
171 
172  if ( IsControlBackground() )
174  else
175  SetBackground( pParent->GetBackground() );
176  }
177 }
178 
180 {
181  if( HasLayoutData() )
182  {
184  mpTabCtrlData->maLayoutPageIdToLine.clear();
185  mpTabCtrlData->maLayoutLineToPageId.clear();
186  }
187 }
188 
191 {
192  ImplInit( pParent, nStyle );
193  SAL_INFO( "vcl", "*** TABCONTROL no notabs? " << (( GetStyle() & WB_NOBORDER ) ? "true" : "false") );
194 }
195 
197 {
198  disposeOnce();
199 }
200 
202 {
203  Window *pParent = GetParent();
204  if (pParent && pParent->IsDialog())
205  GetParent()->RemoveChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
206 
208 
209  // delete TabCtrl data
210  if (mpTabCtrlData)
211  mpTabCtrlData->mpListBox.disposeAndClear();
212  mpTabCtrlData.reset();
214 }
215 
216 ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const
217 {
218  for (auto & item : mpTabCtrlData->maItemList)
219  {
220  if (item.id() == nId)
221  return &item;
222  }
223 
224  return nullptr;
225 }
226 
228 {
229  pItem->maFormatText = pItem->maText;
230  Size aSize( GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
231  Size aImageSize( 0, 0 );
232  if( !!pItem->maTabImage )
233  {
234  aImageSize = pItem->maTabImage.GetSizePixel();
235  if( !pItem->maFormatText.isEmpty() )
236  aImageSize.AdjustWidth(GetTextHeight()/4 );
237  }
238  aSize.AdjustWidth(aImageSize.Width() );
239  if( aImageSize.Height() > aSize.Height() )
240  aSize.setHeight( aImageSize.Height() );
241 
242  aSize.AdjustWidth(TAB_TABOFFSET_X*2 );
243  aSize.AdjustHeight(TAB_TABOFFSET_Y*2 );
244 
245  tools::Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
246  tools::Rectangle aBoundingRgn, aContentRgn;
248  aSize.Width() - TAB_TABOFFSET_X * 2,
249  aSize.Height() - TAB_TABOFFSET_Y * 2));
251  ControlState::ENABLED, aControlValue,
252  aBoundingRgn, aContentRgn ) )
253  {
254  return aContentRgn.GetSize();
255  }
256 
257  // For languages with short names (e.g. Chinese), because the space is
258  // normally only one pixel per char
259  if ( pItem->maFormatText.getLength() < TAB_EXTRASPACE_X )
260  aSize.AdjustWidth(TAB_EXTRASPACE_X-pItem->maFormatText.getLength() );
261 
262  // shorten Text if needed
263  if ( aSize.Width()+4 >= nMaxWidth )
264  {
265  OUString aAppendStr("...");
266  pItem->maFormatText += aAppendStr;
267  do
268  {
269  if (pItem->maFormatText.getLength() > aAppendStr.getLength())
270  pItem->maFormatText = pItem->maFormatText.replaceAt( pItem->maFormatText.getLength()-aAppendStr.getLength()-1, 1, "" );
271  aSize.setWidth( GetCtrlTextWidth( pItem->maFormatText ) );
272  aSize.AdjustWidth(aImageSize.Width() );
273  aSize.AdjustWidth(TAB_TABOFFSET_X*2 );
274  }
275  while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.getLength() > aAppendStr.getLength()) );
276  if ( aSize.Width()+4 >= nMaxWidth )
277  {
278  pItem->maFormatText = ".";
279  aSize.setWidth( 1 );
280  }
281  }
282 
283  if( pItem->maFormatText.isEmpty() )
284  {
285  if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
286  aSize.setHeight( aImageSize.Height()+4 );
287  }
288 
289  return aSize;
290 }
291 
292 // Feel free to move this to some more general place for reuse
293 // http://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
294 // Mostly based on Alexey Frunze's nifty example at
295 // http://stackoverflow.com/questions/9071205/balanced-word-wrap-minimum-raggedness-in-php
297 {
298  static std::deque<size_t> GetEndOfLineIndexes(const std::vector<sal_Int32>& rWidthsOf, sal_Int32 nLineWidth)
299  {
300  ++nLineWidth;
301 
302  size_t nWidthsCount = rWidthsOf.size();
303  std::vector<sal_Int32> aCosts(nWidthsCount * nWidthsCount);
304 
305  // cost function c(i, j) that computes the cost of a line consisting of
306  // the words Word[i] to Word[j]
307  for (size_t i = 0; i < nWidthsCount; ++i)
308  {
309  for (size_t j = 0; j < nWidthsCount; ++j)
310  {
311  if (j >= i)
312  {
313  sal_Int32 c = nLineWidth - (j - i);
314  for (size_t k = i; k <= j; ++k)
315  c -= rWidthsOf[k];
316  c = (c >= 0) ? c * c : SAL_MAX_INT32;
317  aCosts[j * nWidthsCount + i] = c;
318  }
319  else
320  {
321  aCosts[j * nWidthsCount + i] = SAL_MAX_INT32;
322  }
323  }
324  }
325 
326  std::vector<sal_Int32> aFunction(nWidthsCount);
327  std::vector<sal_Int32> aWrapPoints(nWidthsCount);
328 
329  // f(j) in aFunction[], collect wrap points in aWrapPoints[]
330  for (size_t j = 0; j < nWidthsCount; ++j)
331  {
332  aFunction[j] = aCosts[j * nWidthsCount];
333  if (aFunction[j] == SAL_MAX_INT32)
334  {
335  for (size_t k = 0; k < j; ++k)
336  {
337  sal_Int32 s;
338  if (aFunction[k] == SAL_MAX_INT32 || aCosts[j * nWidthsCount + k + 1] == SAL_MAX_INT32)
339  s = SAL_MAX_INT32;
340  else
341  s = aFunction[k] + aCosts[j * nWidthsCount + k + 1];
342  if (aFunction[j] > s)
343  {
344  aFunction[j] = s;
345  aWrapPoints[j] = k + 1;
346  }
347  }
348  }
349  }
350 
351  std::deque<size_t> aSolution;
352 
353  // no solution
354  if (aFunction[nWidthsCount - 1] == SAL_MAX_INT32)
355  return aSolution;
356 
357  // optimal solution
358  size_t j = nWidthsCount - 1;
359  while (true)
360  {
361  aSolution.push_front(j);
362  if (!aWrapPoints[j])
363  break;
364  j = aWrapPoints[j] - 1;
365  }
366 
367  return aSolution;
368  }
369 };
370 
371 static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
372 {
373  if (!ImplGetSVData()->maNWFData.mbCenteredTabs)
374  return;
375 
376  int nRightSpace = nMaxWidth; // space left on the right by the tabs
377  for (auto const& item : pTabCtrlData->maItemList)
378  {
379  if (!item.m_bVisible)
380  continue;
381  nRightSpace -= item.maRect.Right() - item.maRect.Left();
382  }
383  nRightSpace /= 2;
384 
385  for (auto& item : pTabCtrlData->maItemList)
386  {
387  if (!item.m_bVisible)
388  continue;
389  item.maRect.AdjustLeft(nRightSpace);
390  item.maRect.AdjustRight(nRightSpace);
391  }
392 }
393 
395 {
396  if ( nWidth <= 0 )
397  return false;
398  if ( mpTabCtrlData->maItemList.empty() )
399  return false;
400 
401  tools::Long nMaxWidth = nWidth;
402 
403  const tools::Long nOffsetX = 2 + GetItemsOffset().X();
404  const tools::Long nOffsetY = 2 + GetItemsOffset().Y();
405 
406  //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
407  //of ugly bare tabs on lines of their own
408 
409  //collect widths
410  std::vector<sal_Int32> aWidths;
411  for (auto & item : mpTabCtrlData->maItemList)
412  {
413  if (!item.m_bVisible)
414  continue;
415  aWidths.push_back(ImplGetItemSize(&item, nMaxWidth).Width());
416  }
417 
418  //aBreakIndexes will contain the indexes of the last tab on each row
419  std::deque<size_t> aBreakIndexes(MinimumRaggednessWrap::GetEndOfLineIndexes(aWidths, nMaxWidth - nOffsetX - 2));
420 
421  nMaxWidth -= GetItemsOffset().X();
422 
423  tools::Long nX = nOffsetX;
424  tools::Long nY = nOffsetY;
425 
426  sal_uInt16 nLines = 0;
427  sal_uInt16 nCurLine = 0;
428 
429  tools::Long nLineWidthAry[100];
430  sal_uInt16 nLinePosAry[101];
431  nLineWidthAry[0] = 0;
432  nLinePosAry[0] = 0;
433 
434  size_t nIndex = 0;
435 
436  for (auto & item : mpTabCtrlData->maItemList)
437  {
438  if (!item.m_bVisible)
439  continue;
440 
441  Size aSize = ImplGetItemSize( &item, nMaxWidth );
442 
443  bool bNewLine = false;
444  if (!aBreakIndexes.empty() && nIndex > aBreakIndexes.front())
445  {
446  aBreakIndexes.pop_front();
447  bNewLine = true;
448  }
449 
450  if ( bNewLine && (nWidth > 2+nOffsetX) )
451  {
452  if ( nLines == 99 )
453  break;
454 
455  nX = nOffsetX;
456  nY += aSize.Height();
457  nLines++;
458  nLineWidthAry[nLines] = 0;
459  nLinePosAry[nLines] = nIndex;
460  }
461 
462  tools::Rectangle aNewRect( Point( nX, nY ), aSize );
463  if ( mbSmallInvalidate && (item.maRect != aNewRect) )
464  mbSmallInvalidate = false;
465  item.maRect = aNewRect;
466  item.mnLine = nLines;
467  item.mbFullVisible = true;
468 
469  nLineWidthAry[nLines] += aSize.Width();
470  nX += aSize.Width();
471 
472  if (item.id() == mnCurPageId)
473  nCurLine = nLines;
474 
475  ++nIndex;
476  }
477 
478  if (nLines) // two or more lines
479  {
480  tools::Long nLineHeightAry[100];
481  tools::Long nIH = 0;
482  for (const auto& item : mpTabCtrlData->maItemList)
483  {
484  if (!item.m_bVisible)
485  continue;
486  nIH = item.maRect.Bottom() - 1;
487  break;
488  }
489 
490  for ( sal_uInt16 i = 0; i < nLines+1; i++ )
491  {
492  if ( i <= nCurLine )
493  nLineHeightAry[i] = nIH*(nLines-(nCurLine-i)) + GetItemsOffset().Y();
494  else
495  nLineHeightAry[i] = nIH*(i-nCurLine-1) + GetItemsOffset().Y();
496  }
497 
498  nLinePosAry[nLines+1] = static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
499 
500  tools::Long nDX = 0;
501  tools::Long nModDX = 0;
502  tools::Long nIDX = 0;
503 
504  sal_uInt16 i = 0;
505  sal_uInt16 n = 0;
506 
507  for (auto & item : mpTabCtrlData->maItemList)
508  {
509  if (!item.m_bVisible)
510  continue;
511 
512  if ( i == nLinePosAry[n] )
513  {
514  if ( n == nLines+1 )
515  break;
516 
517  nIDX = 0;
518  if( nLinePosAry[n+1]-i > 0 )
519  {
520  nDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) / ( nLinePosAry[n+1] - i );
521  nModDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) % ( nLinePosAry[n+1] - i );
522  }
523  else
524  {
525  // FIXME: this is a case of tabctrl way too small
526  nDX = 0;
527  nModDX = 0;
528  }
529  n++;
530  }
531 
532  item.maRect.AdjustLeft(nIDX );
533  item.maRect.AdjustRight(nIDX + nDX );
534  item.maRect.SetTop( nLineHeightAry[n-1] );
535  item.maRect.SetBottom(nLineHeightAry[n-1] + nIH - 1);
536  nIDX += nDX;
537 
538  if ( nModDX )
539  {
540  nIDX++;
541  item.maRect.AdjustRight( 1 );
542  nModDX--;
543  }
544 
545  i++;
546  }
547  }
548  else // only one line
549  lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
550 
551  return true;
552 }
553 
555 {
556  Size aWinSize = Control::GetOutputSizePixel();
557  if ( nWidth < 0 )
558  nWidth = aWinSize.Width();
559  if ( nHeight < 0 )
560  nHeight = aWinSize.Height();
561 
562  if ( mpTabCtrlData->maItemList.empty() )
563  {
564  tools::Long nW = nWidth-TAB_OFFSET*2;
565  tools::Long nH = nHeight-TAB_OFFSET*2;
566  return (nW > 0 && nH > 0)
567  ? tools::Rectangle(Point(TAB_OFFSET, TAB_OFFSET), Size(nW, nH))
568  : tools::Rectangle();
569  }
570 
571  if ( nItemPos == TAB_PAGERECT )
572  {
573  sal_uInt16 nLastPos;
574  if ( mnCurPageId )
575  nLastPos = GetPagePos( mnCurPageId );
576  else
577  nLastPos = 0;
578 
579  tools::Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
580  if (aRect.IsEmpty())
581  return aRect;
582 
583  tools::Long nW = nWidth-TAB_OFFSET*2;
584  tools::Long nH = nHeight-aRect.Bottom()-TAB_OFFSET*2;
585  return (nW > 0 && nH > 0)
586  ? tools::Rectangle( Point( TAB_OFFSET, aRect.Bottom()+TAB_OFFSET ), Size( nW, nH ) )
587  : tools::Rectangle();
588  }
589 
590  ImplTabItem* const pItem = (nItemPos < mpTabCtrlData->maItemList.size())
591  ? &mpTabCtrlData->maItemList[nItemPos] : nullptr;
592  return ImplGetTabRect(pItem, nWidth, nHeight);
593 }
594 
596 {
597  if ((nWidth <= 1) || (nHeight <= 0) || !pItem || !pItem->m_bVisible)
598  return tools::Rectangle();
599 
600  nWidth -= 1;
601 
602  if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
603  {
604  vcl::Font aFont( GetFont() );
605  aFont.SetTransparent( true );
606  SetFont( aFont );
607 
608  bool bRet = ImplPlaceTabs( nWidth );
609  if ( !bRet )
610  return tools::Rectangle();
611 
612  mnLastWidth = nWidth;
613  mnLastHeight = nHeight;
614  mbFormat = false;
615  }
616 
617  return pItem->maRect;
618 }
619 
620 void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId )
621 {
623 
624  ImplTabItem* pOldItem = ImplGetItem( nOldId );
625  ImplTabItem* pItem = ImplGetItem( nId );
626  TabPage* pOldPage = pOldItem ? pOldItem->mpTabPage.get() : nullptr;
627  TabPage* pPage = pItem ? pItem->mpTabPage.get() : nullptr;
628  vcl::Window* pCtrlParent = GetParent();
629 
630  if ( IsReallyVisible() && IsUpdateMode() )
631  {
632  sal_uInt16 nPos = GetPagePos( nId );
633  tools::Rectangle aRect = ImplGetTabRect( nPos );
634 
635  if ( !pOldItem || !pItem || (pOldItem->mnLine != pItem->mnLine) )
636  {
637  aRect.SetLeft( 0 );
638  aRect.SetTop( 0 );
640  }
641  else
642  {
643  aRect.AdjustLeft( -3 );
644  aRect.AdjustTop( -2 );
645  aRect.AdjustRight(3 );
646  Invalidate( aRect );
647  nPos = GetPagePos( nOldId );
648  aRect = ImplGetTabRect( nPos );
649  aRect.AdjustLeft( -3 );
650  aRect.AdjustTop( -2 );
651  aRect.AdjustRight(3 );
652  }
653  Invalidate( aRect );
654  }
655 
656  if ( pOldPage == pPage )
657  return;
658 
660 
661  if ( pOldPage )
662  {
663  if ( mbRestoreHelpId )
664  pCtrlParent->SetHelpId( OString() );
665  }
666 
667  if ( pPage )
668  {
669  if ( GetStyle() & WB_NOBORDER )
670  {
671  tools::Rectangle aRectNoTab(Point(0, 0), GetSizePixel());
672  pPage->SetPosSizePixel( aRectNoTab.TopLeft(), aRectNoTab.GetSize() );
673  }
674  else
675  pPage->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() );
676 
677  // activate page here so the controls can be switched
678  // also set the help id of the parent window to that of the tab page
679  if ( GetHelpId().isEmpty() )
680  {
681  mbRestoreHelpId = true;
682  pCtrlParent->SetHelpId( pPage->GetHelpId() );
683  }
684 
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  tools::Long nTextHeight = GetTextHeight();
762  tools::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  tools::Long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
789  tools::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  tools::Long nLeftBottom = aRect.Bottom();
810  tools::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  tools::Long nTextHeight = rRenderContext.GetTextHeight();
952  tools::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  tools::Long nXPos = aRect.Left() + ((aTabSize.Width() - nTextWidth - aImageSize.Width()) / 2) - nOff - nOff3;
960  tools::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 || !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  tools::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  tools::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  tools::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  tools::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 
1335 void TabControl::SetPosPixel(const Point& rPos)
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(), OString());
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 
1525 ImplTabItem* TabControl::ImplGetItem(const Point& rPt) const
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  if( rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE )
1546  {
1547  const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
1548  if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1549  {
1550  // trigger redraw if mouse over state has changed
1552  {
1555  if ((pItem != pLastItem) || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
1556  {
1557  vcl::Region aClipRgn;
1558  if (pLastItem)
1559  {
1560  // allow for slightly bigger tabitems
1561  // as used by gtk
1562  // TODO: query for the correct sizes
1563  tools::Rectangle aRect(pLastItem->maRect);
1564  aRect.AdjustLeft( -2 );
1565  aRect.AdjustRight(2 );
1566  aRect.AdjustTop( -3 );
1567  aClipRgn.Union( aRect );
1568  }
1569 
1570  if (pItem)
1571  {
1572  // allow for slightly bigger tabitems
1573  // as used by gtk
1574  // TODO: query for the correct sizes
1575  tools::Rectangle aRect(pItem->maRect);
1576  aRect.AdjustLeft( -2 );
1577  aRect.AdjustRight(2 );
1578  aRect.AdjustTop( -3 );
1579  aClipRgn.Union( aRect );
1580  }
1581 
1582  if( !aClipRgn.IsEmpty() )
1583  Invalidate( aClipRgn );
1584  }
1585  }
1586  }
1587  }
1588 
1589  return Control::PreNotify(rNEvt);
1590 }
1591 
1593 {
1594  bool bRet = false;
1595 
1596  if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
1597  bRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1598 
1599  return bRet || Control::EventNotify( rNEvt );
1600 }
1601 
1603 {
1604  maActivateHdl.Call( this );
1605 }
1606 
1608 {
1609  return !maDeactivateHdl.IsSet() || maDeactivateHdl.Call( this );
1610 }
1611 
1613 {
1615 
1616  Size aNewSize( rSize );
1617  aNewSize.AdjustWidth(TAB_OFFSET*2 );
1619  aNewSize.Width(), aNewSize.Height() );
1620  aNewSize.AdjustHeight(aRect.Top()+TAB_OFFSET );
1621  Window::SetOutputSizePixel( aNewSize );
1622 }
1623 
1624 void TabControl::InsertPage( sal_uInt16 nPageId, const OUString& rText,
1625  sal_uInt16 nPos )
1626 {
1627  SAL_WARN_IF( !nPageId, "vcl", "TabControl::InsertPage(): PageId == 0" );
1628  SAL_WARN_IF( GetPagePos( nPageId ) != TAB_PAGE_NOTFOUND, "vcl",
1629  "TabControl::InsertPage(): PageId already exists" );
1630 
1631  // insert new page item
1632  ImplTabItem* pItem = nullptr;
1633  if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1634  {
1635  mpTabCtrlData->maItemList.emplace_back(nPageId);
1636  pItem = &mpTabCtrlData->maItemList.back();
1637  if( mpTabCtrlData->mpListBox )
1638  mpTabCtrlData->mpListBox->InsertEntry( rText );
1639  }
1640  else
1641  {
1642  std::vector< ImplTabItem >::iterator new_it =
1643  mpTabCtrlData->maItemList.emplace(mpTabCtrlData->maItemList.begin() + nPos, nPageId);
1644  pItem = &(*new_it);
1645  if( mpTabCtrlData->mpListBox )
1646  mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1647  }
1648  if( mpTabCtrlData->mpListBox )
1649  {
1650  if( ! mnCurPageId )
1651  mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1652  mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1653  }
1654 
1655  // set current page id
1656  if ( !mnCurPageId )
1657  mnCurPageId = nPageId;
1658 
1659  // init new page item
1660  pItem->maText = rText;
1661  pItem->mbFullVisible = false;
1662 
1663  mbFormat = true;
1664  if ( IsUpdateMode() )
1665  Invalidate();
1666 
1668  if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1669  Resize();
1670 
1671  CallEventListeners( VclEventId::TabpageInserted, reinterpret_cast<void*>(nPageId) );
1672 }
1673 
1674 void TabControl::RemovePage( sal_uInt16 nPageId )
1675 {
1676  sal_uInt16 nPos = GetPagePos( nPageId );
1677 
1678  // does the item exist ?
1679  if ( nPos == TAB_PAGE_NOTFOUND )
1680  return;
1681 
1682  //remove page item
1683  std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1684  bool bIsCurrentPage = (it->id() == mnCurPageId);
1685  mpTabCtrlData->maItemList.erase( it );
1686  if( mpTabCtrlData->mpListBox )
1687  {
1688  mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1689  mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1690  }
1691 
1692  // If current page is removed, then first page gets the current page
1693  if ( bIsCurrentPage )
1694  {
1695  mnCurPageId = 0;
1696 
1697  if( ! mpTabCtrlData->maItemList.empty() )
1698  {
1699  // don't do this by simply setting mnCurPageId to pFirstItem->id()
1700  // this leaves a lot of stuff (such trivia as _showing_ the new current page) undone
1701  // instead, call SetCurPageId
1702  // without this, the next (outside) call to SetCurPageId with the id of the first page
1703  // will result in doing nothing (as we assume that nothing changed, then), and the page
1704  // will never be shown.
1705  // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1706 
1707  SetCurPageId(mpTabCtrlData->maItemList[0].id());
1708  }
1709  }
1710 
1711  mbFormat = true;
1712  if ( IsUpdateMode() )
1713  Invalidate();
1714 
1716 
1717  CallEventListeners( VclEventId::TabpageRemoved, reinterpret_cast<void*>(nPageId) );
1718 }
1719 
1720 void TabControl::SetPageEnabled( sal_uInt16 i_nPageId, bool i_bEnable )
1721 {
1722  ImplTabItem* pItem = ImplGetItem( i_nPageId );
1723 
1724  if (!pItem || pItem->m_bEnabled == i_bEnable)
1725  return;
1726 
1727  pItem->m_bEnabled = i_bEnable;
1728  if (!pItem->m_bVisible)
1729  return;
1730 
1731  mbFormat = true;
1732  if( mpTabCtrlData->mpListBox )
1733  mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1735 
1736  // SetCurPageId will change to a valid page
1737  if (pItem->id() == mnCurPageId)
1739  else if ( IsUpdateMode() )
1740  Invalidate();
1741 }
1742 
1743 void TabControl::SetPageVisible( sal_uInt16 nPageId, bool bVisible )
1744 {
1745  ImplTabItem* pItem = ImplGetItem( nPageId );
1746  if (!pItem || pItem->m_bVisible == bVisible)
1747  return;
1748 
1749  pItem->m_bVisible = bVisible;
1750  if (!bVisible)
1751  {
1752  if (pItem->mbFullVisible)
1753  mbSmallInvalidate = false;
1754  pItem->mbFullVisible = false;
1755  pItem->maRect.SetEmpty();
1756  }
1757  mbFormat = true;
1758 
1759  // SetCurPageId will change to a valid page
1760  if (pItem->id() == mnCurPageId)
1762  else if (IsUpdateMode())
1763  Invalidate();
1764 }
1765 
1766 sal_uInt16 TabControl::GetPageCount() const
1767 {
1768  return static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
1769 }
1770 
1771 sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1772 {
1773  if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1774  return mpTabCtrlData->maItemList[nPos].id();
1775  return 0;
1776 }
1777 
1778 sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1779 {
1780  sal_uInt16 nPos = 0;
1781  for (auto const& item : mpTabCtrlData->maItemList)
1782  {
1783  if (item.id() == nPageId)
1784  return nPos;
1785  ++nPos;
1786  }
1787 
1788  return TAB_PAGE_NOTFOUND;
1789 }
1790 
1791 sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1792 {
1793  const auto &rList = mpTabCtrlData->maItemList;
1794  const auto it = std::find_if(rList.begin(), rList.end(), [&rPos, this](const auto &item) {
1795  return const_cast<TabControl*>(this)->ImplGetTabRect(&item).IsInside(rPos); });
1796  return (it != rList.end()) ? it->id() : 0;
1797 }
1798 
1799 sal_uInt16 TabControl::GetPageId( const OString& rName ) const
1800 {
1801  const auto &rList = mpTabCtrlData->maItemList;
1802  const auto it = std::find_if(rList.begin(), rList.end(), [&rName](const auto &item) {
1803  return item.maTabName == rName; });
1804  return (it != rList.end()) ? it->id() : 0;
1805 }
1806 
1807 void TabControl::SetCurPageId( sal_uInt16 nPageId )
1808 {
1809  sal_uInt16 nPos = GetPagePos( nPageId );
1810  while (nPos != TAB_PAGE_NOTFOUND && !mpTabCtrlData->maItemList[nPos].m_bEnabled)
1811  {
1812  nPos++;
1813  if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1814  nPos = 0;
1815  if (mpTabCtrlData->maItemList[nPos].id() == nPageId)
1816  break;
1817  }
1818 
1819  if( nPos == TAB_PAGE_NOTFOUND )
1820  return;
1821 
1822  nPageId = mpTabCtrlData->maItemList[nPos].id();
1823  if ( nPageId == mnCurPageId )
1824  {
1825  if ( mnActPageId )
1826  mnActPageId = nPageId;
1827  return;
1828  }
1829 
1830  if ( mnActPageId )
1831  mnActPageId = nPageId;
1832  else
1833  {
1834  mbFormat = true;
1835  sal_uInt16 nOldId = mnCurPageId;
1836  mnCurPageId = nPageId;
1837  ImplChangeTabPage( nPageId, nOldId );
1838  }
1839 }
1840 
1841 sal_uInt16 TabControl::GetCurPageId() const
1842 {
1843  if ( mnActPageId )
1844  return mnActPageId;
1845  else
1846  return mnCurPageId;
1847 }
1848 
1849 void TabControl::SelectTabPage( sal_uInt16 nPageId )
1850 {
1851  if ( !nPageId || (nPageId == mnCurPageId) )
1852  return;
1853 
1855 
1856  CallEventListeners( VclEventId::TabpageDeactivate, reinterpret_cast<void*>(mnCurPageId) );
1857  if ( DeactivatePage() )
1858  {
1859  mnActPageId = nPageId;
1860  ActivatePage();
1861  // Page could have been switched by the Activate handler
1862  nPageId = mnActPageId;
1863  mnActPageId = 0;
1864  SetCurPageId( nPageId );
1865  if( mpTabCtrlData->mpListBox )
1866  mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1867  CallEventListeners( VclEventId::TabpageActivate, reinterpret_cast<void*>(nPageId) );
1868  }
1869 }
1870 
1871 void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1872 {
1873  ImplTabItem* pItem = ImplGetItem( nPageId );
1874 
1875  if ( !pItem || (pItem->mpTabPage.get() == pTabPage) )
1876  return;
1877 
1878  if ( pTabPage )
1879  {
1880  if ( IsDefaultSize() )
1881  SetTabPageSizePixel( pTabPage->GetSizePixel() );
1882 
1883  // only set here, so that Resize does not reposition TabPage
1884  pItem->mpTabPage = pTabPage;
1885  queue_resize();
1886 
1887  if (pItem->id() == mnCurPageId)
1888  ImplChangeTabPage(pItem->id(), 0);
1889  }
1890  else
1891  {
1892  pItem->mpTabPage = nullptr;
1893  queue_resize();
1894  }
1895 }
1896 
1897 TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1898 {
1899  ImplTabItem* pItem = ImplGetItem( nPageId );
1900 
1901  if ( pItem )
1902  return pItem->mpTabPage;
1903  else
1904  return nullptr;
1905 }
1906 
1907 void TabControl::SetPageText( sal_uInt16 nPageId, const OUString& rText )
1908 {
1909  ImplTabItem* pItem = ImplGetItem( nPageId );
1910 
1911  if ( !pItem || pItem->maText == rText )
1912  return;
1913 
1914  pItem->maText = rText;
1915  mbFormat = true;
1916  if( mpTabCtrlData->mpListBox )
1917  {
1918  sal_uInt16 nPos = GetPagePos( nPageId );
1919  mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1920  mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
1921  }
1922  if ( IsUpdateMode() )
1923  Invalidate();
1925  CallEventListeners( VclEventId::TabpagePageTextChanged, reinterpret_cast<void*>(nPageId) );
1926 }
1927 
1928 OUString const & TabControl::GetPageText( sal_uInt16 nPageId ) const
1929 {
1930  ImplTabItem* pItem = ImplGetItem( nPageId );
1931 
1932  assert( pItem );
1933 
1934  return pItem->maText;
1935 }
1936 
1937 void TabControl::SetHelpText( sal_uInt16 nPageId, const OUString& rText )
1938 {
1939  ImplTabItem* pItem = ImplGetItem( nPageId );
1940 
1941  assert( pItem );
1942 
1943  pItem->maHelpText = rText;
1944 }
1945 
1946 const OUString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
1947 {
1948  ImplTabItem* pItem = ImplGetItem( nPageId );
1949  assert( pItem );
1950  return pItem->maHelpText;
1951 }
1952 
1953 void TabControl::SetAccessibleName(sal_uInt16 nPageId, const OUString& rName)
1954 {
1955  ImplTabItem* pItem = ImplGetItem( nPageId );
1956  assert( pItem );
1957  pItem->maAccessibleName = rName;
1958 }
1959 
1960 OUString TabControl::GetAccessibleName( sal_uInt16 nPageId ) const
1961 {
1962  ImplTabItem* pItem = ImplGetItem( nPageId );
1963  assert( pItem );
1964  if (!pItem->maAccessibleName.isEmpty())
1965  return pItem->maAccessibleName;
1967 }
1968 
1969 void TabControl::SetAccessibleDescription(sal_uInt16 nPageId, const OUString& rDesc)
1970 {
1971  ImplTabItem* pItem = ImplGetItem( nPageId );
1972  assert( pItem );
1973  pItem->maAccessibleDescription = rDesc;
1974 }
1975 
1976 OUString TabControl::GetAccessibleDescription( sal_uInt16 nPageId ) const
1977 {
1978  ImplTabItem* pItem = ImplGetItem( nPageId );
1979  assert( pItem );
1980  if (!pItem->maAccessibleDescription.isEmpty())
1981  return pItem->maAccessibleDescription;
1982  return pItem->maHelpText;
1983 }
1984 
1985 void TabControl::SetPageName( sal_uInt16 nPageId, const OString& rName ) const
1986 {
1987  ImplTabItem* pItem = ImplGetItem( nPageId );
1988 
1989  if ( pItem )
1990  pItem->maTabName = rName;
1991 }
1992 
1993 OString TabControl::GetPageName( sal_uInt16 nPageId ) const
1994 {
1995  ImplTabItem* pItem = ImplGetItem( nPageId );
1996 
1997  if (pItem)
1998  return pItem->maTabName;
1999 
2000  return OString();
2001 }
2002 
2003 void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2004 {
2005  ImplTabItem* pItem = ImplGetItem( i_nPageId );
2006 
2007  if ( pItem )
2008  {
2009  pItem->maTabImage = i_rImage;
2010  mbFormat = true;
2011  if ( IsUpdateMode() )
2012  Invalidate();
2013  }
2014 }
2015 
2017 {
2018  tools::Rectangle aRet;
2019 
2020  if( !HasLayoutData() || mpTabCtrlData->maLayoutPageIdToLine.empty() )
2021  FillLayoutData();
2022 
2023  if( HasLayoutData() )
2024  {
2025  std::unordered_map< int, int >::const_iterator it = mpTabCtrlData->maLayoutPageIdToLine.find( static_cast<int>(nPageId) );
2026  if( it != mpTabCtrlData->maLayoutPageIdToLine.end() )
2027  {
2028  Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( it->second );
2029  if( (aPair.B() - aPair.A()) >= nIndex )
2030  aRet = mpControlData->mpLayoutData->GetCharacterBounds( aPair.A() + nIndex );
2031  }
2032  }
2033 
2034  return aRet;
2035 }
2036 
2037 tools::Long TabControl::GetIndexForPoint( const Point& rPoint, sal_uInt16& rPageId ) const
2038 {
2039  tools::Long nRet = -1;
2040 
2041  if( !HasLayoutData() || mpTabCtrlData->maLayoutPageIdToLine.empty() )
2042  FillLayoutData();
2043 
2044  if( HasLayoutData() )
2045  {
2046  int nIndex = mpControlData->mpLayoutData->GetIndexForPoint( rPoint );
2047  if( nIndex != -1 )
2048  {
2049  // what line (->pageid) is this index in ?
2050  int nLines = mpControlData->mpLayoutData->GetLineCount();
2051  int nLine = -1;
2052  while( ++nLine < nLines )
2053  {
2054  Pair aPair = mpControlData->mpLayoutData->GetLineStartEnd( nLine );
2055  if( aPair.A() <= nIndex && aPair.B() >= nIndex )
2056  {
2057  nRet = nIndex - aPair.A();
2058  rPageId = static_cast<sal_uInt16>(mpTabCtrlData->maLayoutLineToPageId[ nLine ]);
2059  break;
2060  }
2061  }
2062  }
2063  }
2064 
2065  return nRet;
2066 }
2067 
2069 {
2070  mpTabCtrlData->maLayoutLineToPageId.clear();
2071  mpTabCtrlData->maLayoutPageIdToLine.clear();
2072  const_cast<TabControl*>(this)->Invalidate();
2073 }
2074 
2075 tools::Rectangle TabControl::GetTabBounds( sal_uInt16 nPageId ) const
2076 {
2077  tools::Rectangle aRet;
2078 
2079  ImplTabItem* pItem = ImplGetItem( nPageId );
2080  if (pItem && pItem->m_bVisible)
2081  aRet = pItem->maRect;
2082 
2083  return aRet;
2084 }
2085 
2086 void TabControl::SetItemsOffset( const Point& rOffs )
2087 {
2088  if( mpTabCtrlData )
2089  mpTabCtrlData->maItemsOffset = rOffs;
2090 }
2091 
2093 {
2094  if( mpTabCtrlData )
2095  return mpTabCtrlData->maItemsOffset;
2096  else
2097  return Point();
2098 }
2099 
2100 Size TabControl::ImplCalculateRequisition(sal_uInt16& nHeaderHeight) const
2101 {
2102  Size aOptimalPageSize(0, 0);
2103 
2104  sal_uInt16 nOrigPageId = GetCurPageId();
2105  for (auto const& item : mpTabCtrlData->maItemList)
2106  {
2107  const TabPage *pPage = item.mpTabPage;
2108  //it's a real nuisance if the page is not inserted yet :-(
2109  //We need to force all tabs to exist to get overall optimal size for dialog
2110  if (!pPage)
2111  {
2112  TabControl *pThis = const_cast<TabControl*>(this);
2113  pThis->SetCurPageId(item.id());
2114  pThis->ActivatePage();
2115  pPage = item.mpTabPage;
2116  }
2117 
2118  if (!pPage)
2119  continue;
2120 
2121  Size aPageSize(VclContainer::getLayoutRequisition(*pPage));
2122 
2123  if (aPageSize.Width() > aOptimalPageSize.Width())
2124  aOptimalPageSize.setWidth( aPageSize.Width() );
2125  if (aPageSize.Height() > aOptimalPageSize.Height())
2126  aOptimalPageSize.setHeight( aPageSize.Height() );
2127  }
2128 
2129  //fdo#61940 If we were forced to activate pages in order to on-demand
2130  //create them to get their optimal size, then switch back to the original
2131  //page and re-activate it
2132  if (nOrigPageId != GetCurPageId())
2133  {
2134  TabControl *pThis = const_cast<TabControl*>(this);
2135  pThis->SetCurPageId(nOrigPageId);
2136  pThis->ActivatePage();
2137  }
2138 
2139  tools::Long nTabLabelsBottom = 0, nTabLabelsRight = 0;
2140  for (sal_uInt16 nPos(0), sizeList(static_cast <sal_uInt16> (mpTabCtrlData->maItemList.size()));
2141  nPos < sizeList; ++nPos)
2142  {
2143  TabControl* pThis = const_cast<TabControl*>(this);
2144 
2145  tools::Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aOptimalPageSize.Width(), LONG_MAX);
2146  if (aTabRect.Bottom() > nTabLabelsBottom)
2147  {
2148  nTabLabelsBottom = aTabRect.Bottom();
2149  nHeaderHeight = nTabLabelsBottom;
2150  }
2151  if (!aTabRect.IsEmpty() && aTabRect.Right() > nTabLabelsRight)
2152  nTabLabelsRight = aTabRect.Right();
2153  }
2154 
2155  Size aOptimalSize(aOptimalPageSize);
2156  aOptimalSize.AdjustHeight(nTabLabelsBottom );
2157  aOptimalSize.setWidth( std::max(nTabLabelsRight, aOptimalSize.Width()) );
2158 
2159  aOptimalSize.AdjustWidth(TAB_OFFSET * 2 );
2160  aOptimalSize.AdjustHeight(TAB_OFFSET * 2 );
2161 
2162  return aOptimalSize;
2163 }
2164 
2166 {
2167  sal_uInt16 nHeaderHeight;
2168  return ImplCalculateRequisition(nHeaderHeight);
2169 }
2170 
2172 {
2173  return calculateRequisition();
2174 }
2175 
2177 {
2178  mbLayoutDirty = true;
2179  Window::queue_resize(eReason);
2180 }
2181 
2182 std::vector<sal_uInt16> TabControl::GetPageIDs() const
2183 {
2184  std::vector<sal_uInt16> aIDs;
2185  for (auto const& item : mpTabCtrlData->maItemList)
2186  {
2187  aIDs.push_back(item.id());
2188  }
2189 
2190  return aIDs;
2191 }
2192 
2194 {
2196 }
2197 
2199 {
2200  Control::DumpAsPropertyTree(rJsonWriter);
2201  {
2202  auto tabsNode = rJsonWriter.startNode("tabs");
2203  for(auto id : GetPageIDs())
2204  {
2205  auto tabNode = rJsonWriter.startNode("");
2206  rJsonWriter.put("text", GetPageText(id));
2207  rJsonWriter.put("id", id);
2208  rJsonWriter.put("name", GetPageName(id));
2209  }
2210  }
2211  rJsonWriter.put("selected", GetCurPageId());
2212 }
2213 
2214 sal_uInt16 NotebookbarTabControlBase::m_nHeaderHeight = 0;
2215 
2216 IMPL_LINK_NOARG(NotebookbarTabControlBase, OpenMenu, Button*, void)
2217 {
2218  m_aIconClickHdl.Call(static_cast<NotebookBar*>(GetParent()->GetParent()));
2219 }
2220 
2221 NotebookbarTabControlBase::NotebookbarTabControlBase(vcl::Window* pParent)
2222  : TabControl(pParent, WB_STDTABCONTROL)
2223  , bLastContextWasSupported(true)
2224  , eLastContext(vcl::EnumContext::Context::Any)
2225 {
2226  m_pOpenMenu = VclPtr<PushButton>::Create( this , WB_CENTER | WB_VCENTER );
2227  m_pOpenMenu->SetClickHdl(LINK(this, NotebookbarTabControlBase, OpenMenu));
2228  m_pOpenMenu->SetModeImage(Image(StockImage::Yes, SV_RESID_BITMAP_NOTEBOOKBAR));
2229  m_pOpenMenu->SetSizePixel(m_pOpenMenu->GetOptimalSize());
2230  m_pOpenMenu->Show();
2231 }
2232 
2233 NotebookbarTabControlBase::~NotebookbarTabControlBase()
2234 {
2235  disposeOnce();
2236 }
2237 
2238 void NotebookbarTabControlBase::SetContext( vcl::EnumContext::Context eContext )
2239 {
2240  if (eLastContext == eContext)
2241  return;
2242 
2243  bool bHandled = false;
2244 
2245  for (int nChild = 0; nChild < GetPageCount(); ++nChild)
2246  {
2247  sal_uInt16 nPageId = TabControl::GetPageId(nChild);
2248  TabPage* pPage = GetTabPage(nPageId);
2249 
2250  if (pPage)
2251  {
2252  SetPageVisible(nPageId, pPage->HasContext(eContext) || pPage->HasContext(vcl::EnumContext::Context::Any));
2253 
2254  if (!bHandled && bLastContextWasSupported
2256  {
2257  SetCurPageId(nPageId);
2258  }
2259 
2260  if (pPage->HasContext(eContext) && eContext != vcl::EnumContext::Context::Any)
2261  {
2262  SetCurPageId(nPageId);
2263  bHandled = true;
2264  bLastContextWasSupported = true;
2265  }
2266  }
2267  }
2268 
2269  if (!bHandled)
2270  bLastContextWasSupported = false;
2271  eLastContext = eContext;
2272 }
2273 
2274 void NotebookbarTabControlBase::dispose()
2275 {
2276  m_pShortcuts.disposeAndClear();
2277  m_pOpenMenu.disposeAndClear();
2279 }
2280 
2281 void NotebookbarTabControlBase::SetToolBox( ToolBox* pToolBox )
2282 {
2283  m_pShortcuts.set( pToolBox );
2284 }
2285 
2286 void NotebookbarTabControlBase::SetIconClickHdl( Link<NotebookBar*, void> aHdl )
2287 {
2288  m_aIconClickHdl = aHdl;
2289 }
2290 
2291 static bool lcl_isValidPage(const ImplTabItem& rItem, bool& bFound)
2292 {
2293  if (rItem.m_bVisible && rItem.m_bEnabled)
2294  bFound = true;
2295  return bFound;
2296 }
2297 
2298 void NotebookbarTabControlBase::ImplActivateTabPage( bool bNext )
2299 {
2300  const sal_uInt16 nOldPos = GetPagePos(GetCurPageId());
2301  bool bFound = false;
2302  sal_Int32 nCurPos = nOldPos;
2303 
2304  if (bNext)
2305  {
2306  for (nCurPos++; nCurPos < GetPageCount(); nCurPos++)
2307  if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2308  break;
2309  }
2310  else
2311  {
2312  for (nCurPos--; nCurPos >= 0; nCurPos--)
2313  if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2314  break;
2315  }
2316 
2317  if (!bFound)
2318  nCurPos = nOldPos;
2319  SelectTabPage( TabControl::GetPageId( nCurPos ) );
2320 }
2321 
2322 sal_uInt16 NotebookbarTabControlBase::GetHeaderHeight()
2323 {
2324  return m_nHeaderHeight;
2325 }
2326 
2327 bool NotebookbarTabControlBase::ImplPlaceTabs( tools::Long nWidth )
2328 {
2329  if ( nWidth <= 0 )
2330  return false;
2331  if ( mpTabCtrlData->maItemList.empty() )
2332  return false;
2333  if (!m_pOpenMenu || m_pOpenMenu->isDisposed())
2334  return false;
2335 
2336  const tools::Long nHamburgerWidth = m_pOpenMenu->GetSizePixel().Width();
2337  tools::Long nMaxWidth = nWidth - nHamburgerWidth;
2338  tools::Long nShortcutsWidth = m_pShortcuts != nullptr ? m_pShortcuts->GetSizePixel().getWidth() + 1 : 0;
2339  tools::Long nFullWidth = nShortcutsWidth;
2340 
2341  const tools::Long nOffsetX = 2 + GetItemsOffset().X() + nShortcutsWidth;
2342  const tools::Long nOffsetY = 2 + GetItemsOffset().Y();
2343 
2344  //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
2345  //of ugly bare tabs on lines of their own
2346 
2347  for (auto & item : mpTabCtrlData->maItemList)
2348  {
2349  tools::Long nTabWidth = 0;
2350  if (item.m_bVisible)
2351  {
2352  nTabWidth = ImplGetItemSize(&item, nMaxWidth).getWidth();
2353  if (!item.maText.isEmpty() && nTabWidth < 100)
2354  nTabWidth = 100;
2355  }
2356  nFullWidth += nTabWidth;
2357  }
2358 
2359  nMaxWidth -= GetItemsOffset().X();
2360 
2361  tools::Long nX = nOffsetX;
2362  tools::Long nY = nOffsetY;
2363 
2364  tools::Long nLineWidthAry[100];
2365  nLineWidthAry[0] = 0;
2366 
2367  for (auto & item : mpTabCtrlData->maItemList)
2368  {
2369  if (!item.m_bVisible)
2370  continue;
2371 
2372  Size aSize = ImplGetItemSize( &item, nMaxWidth );
2373 
2374  // set minimum tab size
2375  if( nFullWidth < nMaxWidth && !item.maText.isEmpty() && aSize.getWidth() < 100)
2376  aSize.setWidth( 100 );
2377 
2378  if( !item.maText.isEmpty() && aSize.getHeight() < 28 )
2379  aSize.setHeight( 28 );
2380 
2381  tools::Rectangle aNewRect( Point( nX, nY ), aSize );
2382  if ( mbSmallInvalidate && (item.maRect != aNewRect) )
2383  mbSmallInvalidate = false;
2384 
2385  item.maRect = aNewRect;
2386  item.mnLine = 0;
2387  item.mbFullVisible = true;
2388 
2389  nLineWidthAry[0] += aSize.Width();
2390  nX += aSize.Width();
2391  }
2392 
2393  // we always have only one line of tabs
2394  lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
2395 
2396  // position the shortcutbox
2397  if (m_pShortcuts)
2398  {
2399  tools::Long nPosY = (m_nHeaderHeight - m_pShortcuts->GetSizePixel().getHeight()) / 2;
2400  m_pShortcuts->SetPosPixel(Point(0, nPosY));
2401  }
2402 
2403  tools::Long nPosY = (m_nHeaderHeight - m_pOpenMenu->GetSizePixel().getHeight()) / 2;
2404  // position the menu
2405  m_pOpenMenu->SetPosPixel(Point(nWidth - nHamburgerWidth, nPosY));
2406 
2407  return true;
2408 }
2409 
2410 Size NotebookbarTabControlBase::calculateRequisition() const
2411 {
2412  return TabControl::ImplCalculateRequisition(m_nHeaderHeight);
2413 }
2414 
2415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Point TopLeft() const
virtual const vcl::Font & GetCanonicalFont(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:134
Size GetSizePixel() const
Definition: Image.cxx:86
const Color & GetTextColor() const
Definition: outdev.hxx:1133
const Color & GetShadowColor() const
bool IsControlBackground() const
Definition: window2.cxx:1087
virtual void queue_resize(StateChangedType eReason=StateChangedType::Layout) override
Definition: tabctrl.cxx:2176
Point GetPointerPosPixel()
Definition: mouse.cxx:550
const Wallpaper & GetBackground() const
Definition: outdev.hxx:643
sal_uInt16 m_nId
Definition: tabctrl.cxx:49
void HideFocus()
Definition: window2.cxx:91
sal_Int32 nIndex
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
bool mbLayoutDirty
Definition: tabctrl.hxx:62
SAL_DLLPRIVATE bool ImplHandleKeyEvent(const KeyEvent &rKeyEvent)
Definition: tabctrl.cxx:993
bool mbSmallInvalidate
Definition: tabctrl.hxx:61
void DrawImage(const Point &rPos, const Image &rImage, DrawImageFlags nStyle=DrawImageFlags::NONE)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Point maItemsOffset
Definition: tabctrl.cxx:84
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long mnLastWidth
Definition: tabctrl.hxx:55
void setWidth(tools::Long nWidth)
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
virtual void SetPosPixel(const Point &rPos) override
Definition: tabctrl.cxx:1335
VclPtr< TabPage > mpTabPage
Definition: tabctrl.cxx:52
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
SAL_DLLPRIVATE void ImplFreeLayoutData()
Definition: tabctrl.cxx:179
virtual const Color & GetCanonicalTextColor(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:139
bool mbNoActiveTabTextRaise
Definition: svdata.hxx:323
void SetHelpId(sal_uInt16 nItemId, const OString &rHelpId)
Definition: menu.cxx:1128
A widget used to choose from a list of items and which has no entry.
Definition: lstbox.hxx:83
WinBits const WB_NODIALOGCONTROL
Point BottomLeft() const
WinBits const WB_NOGROUP
void Union(const tools::Rectangle &rRegion)
Definition: region.cxx:508
tools::Long getWidth() const
SAL_DLLPRIVATE void ImplClearLayoutData() const
Definition: ctrl.cxx:330
void SelectTabPage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1849
static Size getLayoutRequisition(const vcl::Window &rWindow)
Definition: layout.cxx:143
long Long
tools::Long mnLastHeight
Definition: tabctrl.hxx:56
const StyleSettings & GetStyleSettings() const
sal_uInt16 mnActPageId
Definition: tabctrl.hxx:57
static std::deque< size_t > GetEndOfLineIndexes(const std::vector< sal_Int32 > &rWidthsOf, sal_Int32 nLineWidth)
Definition: tabctrl.cxx:298
const OUString & GetHelpText() const
Definition: window.cxx:3074
virtual void StateChanged(StateChangedType nStateChange) override
Definition: ctrl.cxx:260
ImplSVNWFData maNWFData
Definition: svdata.hxx:398
sal_Int64 n
Link< TabControl *, bool > maDeactivateHdl
Definition: tabctrl.hxx:64
void SetPageVisible(sal_uInt16 nPageId, bool bVisible=true)
Definition: tabctrl.cxx:1743
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual Size GetSizePixel() const
Definition: window.cxx:2395
ScopedJsonWriterNode startNode(const char *)
SAL_DLLPRIVATE WindowImpl * ImplGetWindowImpl() const
Definition: window.hxx:563
OUString const & GetPageText(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1928
sal_Int16 nId
TabPage * GetTabPage(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1897
ImplTabItem(sal_uInt16 nId)
Definition: tabctrl.cxx:71
void SetPageEnabled(sal_uInt16 nPageId, bool bEnable=true)
Definition: tabctrl.cxx:1720
#define TAB_BORDER_RIGHT
Definition: tabctrl.hxx:48
sal_uInt16 GetCode() const
Definition: keycod.hxx:51
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
std::unordered_map< int, int > maLayoutPageIdToLine
Definition: tabctrl.cxx:82
void RemoveChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:322
OUString GetAccessibleDescription() const
DataChangedEventType GetType() const
Definition: event.hxx:357
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:311
sal_uInt16 Execute(vcl::Window *pWindow, const Point &rPopupPos)
Definition: menu.cxx:2794
std::unique_ptr< ImplTabCtrlData > mpTabCtrlData
Definition: tabctrl.hxx:54
void SetHelpId(const OString &)
Definition: window2.cxx:823
const Color & GetControlBackground() const
Definition: window2.cxx:1082
virtual Size calculateRequisition() const
Definition: tabctrl.cxx:2165
bool HasChildPathFocus(bool bSystemWindow=false) const
Definition: window.cxx:2988
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
HelpEventMode GetMode() const
Definition: event.hxx:205
void SetRight(tools::Long v)
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1543
virtual Size GetOptimalSize() const override
Definition: tabctrl.cxx:2171
OUString maText
Definition: tabctrl.cxx:53
bool IsEmpty() const
StateChangedType
Definition: window.hxx:317
SAL_DLLPRIVATE ImplTabItem * ImplGetItem(sal_uInt16 nId) const
Definition: tabctrl.cxx:216
void SetAccessibleName(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1953
OUString GetAccessibleName() const
A construction helper for ScopedVclPtr.
Definition: vclptr.hxx:407
sal_Int64 WinBits
void SetBackground()
OString GetPageName(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1993
sal_uInt16 nPageId
OUString maFormatText
Definition: tabctrl.cxx:54
sal_uInt16 GetButtons() const
Definition: event.hxx:144
virtual void LoseFocus() override
Definition: tabctrl.cxx:1362
this flags lets the item be drawn disabled (e.g.
tools::Long Left() const
virtual void DumpAsPropertyTree(tools::JsonWriter &)
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: window.cxx:3333
void SetLeft(tools::Long v)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void SetPageImage(sal_uInt16 nPageId, const Image &rImage)
Definition: tabctrl.cxx:2003
const vcl::Font & GetFont() const
Definition: outdev.hxx:649
bool IsEnterWindow() const
Definition: event.hxx:135
bool mbFullVisible
Definition: tabctrl.cxx:61
bool IsMouseEvent() const
tools::Long GetIndexForPoint(const Point &rPoint, sal_uInt16 &rPageId) const
Definition: tabctrl.cxx:2037
bool IsDefaultSize() const
Definition: window2.cxx:1153
void Hide()
Definition: window.hxx:945
virtual FactoryFunction GetUITestFactory() const override
Definition: tabctrl.cxx:2193
AllSettingsFlags GetFlags() const
Definition: event.hxx:358
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
tools::Long Bottom() const
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1592
const Color & GetLightColor() const
TabitemFlags mnAlignment
virtual void GetFocus() override
Definition: tabctrl.cxx:1347
static bool lcl_isValidPage(const ImplTabItem &rItem, bool &bFound)
Definition: tabctrl.cxx:2291
tools::Long GetCtrlTextWidth(const OUString &rStr, const SalLayoutGlyphs *pLayoutCache=nullptr) const
Definition: text.cxx:2212
bool mbRestoreHelpId
Definition: tabctrl.hxx:60
static bool lcl_canPaint(const vcl::RenderContext &rRenderContext, const tools::Rectangle &rDrawRect, const tools::Rectangle &rItemRect)
Definition: tabctrl.cxx:1073
tools::Rectangle GetCharacterBounds(sal_uInt16 nPageId, tools::Long nIndex) const
Definition: tabctrl.cxx:2016
void SetCurPageId(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1807
virtual void KeyInput(const KeyEvent &rKEvt) override
Definition: tabctrl.cxx:1054
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
Definition: line.cxx:88
OUString maHelpText
Definition: tabctrl.cxx:55
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:58
sal_uInt16 GetPageCount() const
Definition: tabctrl.cxx:1766
bool IsChildTransparentModeEnabled() const
Definition: window2.cxx:1027
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:204
#define TAB_BORDER_BOTTOM
Definition: tabctrl.hxx:49
Point BottomRight() const
const Color & GetDarkShadowColor() const
tools::Long getHeight() const
WinBits const WB_DIALOGCONTROL
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
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
void SetAccessibleDescription(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1969
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: tabctrl.cxx:92
#define SAL_MAX_INT32
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:51
Window(WindowType nType)
Definition: window.cxx:89
void SetInputContext(const InputContext &rInputContext)
Definition: window.cxx:2070
bool IsLeaveWindow() const
Definition: event.hxx:137
int i
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: tabctrl.cxx:1511
SAL_DLLPRIVATE tools::Rectangle ImplGetTabRect(sal_uInt16 nPos, tools::Long nWidth=-1, tools::Long nHeight=-1)
Definition: tabctrl.cxx:554
void SetPageText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1907
virtual bool ImplPlaceTabs(tools::Long nWidth)
Definition: tabctrl.cxx:394
OUString maAccessibleDescription
Definition: tabctrl.cxx:57
Link< TabControl *, void > maActivateHdl
Definition: tabctrl.hxx:63
const vcl::Font & GetTabFont() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
Definition: paint.cxx:1162
SAL_DLLPRIVATE void ImplShowFocus()
Definition: tabctrl.cxx:751
void CallEventListeners(VclEventId nEvent, void *pData=nullptr)
Definition: ctrl.cxx:297
OUString maAccessibleName
Definition: tabctrl.cxx:56
bool IsUpdateMode() const
Definition: window2.cxx:1173
tools::Long Width() const
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:302
virtual void DumpAsPropertyTree(tools::JsonWriter &) override
Dumps itself and potentially its children to a property tree, to be written easily to JSON...
Definition: tabctrl.cxx:2198
CommandEventId GetCommand() const
bool HasContext(const vcl::EnumContext::Context eContext) const
Definition: IContext.hxx:34
bool IsDialog() const
Definition: window2.cxx:1002
void SetTextColor(const Color &rColor)
Definition: text.cxx:666
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
Point GetItemsOffset() const
Definition: tabctrl.cxx:2092
void Intersect(const tools::Rectangle &rRegion)
Definition: region.cxx:584
MouseNotifyEvent GetType() const
Definition: event.hxx:303
bool IsInside(const Point &rPOINT) const
SAL_DLLPRIVATE void ImplChangeTabPage(sal_uInt16 nId, sal_uInt16 nOldId)
Definition: tabctrl.cxx:620
bool DrawNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, const OUString &aCaption, const Color &rBackgroundColor=COL_AUTO)
Request rendering of a particular control and/or part.
void SetTop(tools::Long v)
void SetBottom(tools::Long v)
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: ctrl.cxx:59
WinBits const WB_DROPDOWN
const AllSettings & GetSettings() const
Definition: outdev.hxx:418
void SetPaintTransparent(bool bTransparent)
Definition: paint.cxx:1024
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
DrawTextFlags
Definition: outdev.hxx:142
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
Definition: tabpage.cxx:161
tools::Long Top() const
std::vector< ImplTabItem > maItemList
Definition: tabctrl.cxx:85
virtual void LoseFocus()
Definition: window.cxx:1849
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2810
#define TAB_TABOFFSET_Y
Definition: tabctrl.hxx:44
bool KeyboardActivated() const
Definition: event.hxx:206
void GrabFocus()
Definition: window.cxx:2960
Image maTabImage
Definition: tabctrl.cxx:64
static void ShowQuickHelp(vcl::Window *pParent, const tools::Rectangle &rScreenRect, const OUString &rHelpText, QuickHelpFlags nStyle=QuickHelpFlags::NONE)
Definition: help.cxx:180
void SetTabPageSizePixel(const Size &rSize)
Definition: tabctrl.cxx:1612
virtual void ShowFocus(const tools::Rectangle &rRect)
Definition: window2.cxx:49
vcl::Window * GetParent() const
Definition: window2.cxx:1097
void DrawPixel(const Point &rPt)
Definition: pixel.cxx:54
bool IsReallyShown() const
Definition: window2.cxx:1112
Size GetSize() const
SAL_DLLPRIVATE bool ImplPosCurTabPage()
Definition: tabctrl.cxx:714
const long LONG_MAX
virtual void Resize() override
Definition: tabctrl.cxx:1342
void put(const char *pPropName, const OUString &rPropValue)
sal_uInt16 GetPagePos(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1778
sal_uInt16 id() const
Definition: tabctrl.cxx:68
WinBits const WB_NOBORDER
void CheckItem(sal_uInt16 nItemId, bool bCheck=true)
Definition: menu.cxx:824
const sal_uInt16 idx[]
StyleSettingsOptions GetOptions() const
sal_uInt16 mnLine
Definition: tabctrl.cxx:60
tools::Long AdjustTop(tools::Long nVertMoveDelta)
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
bool mbFormat
Definition: tabctrl.hxx:59
const Point & GetMousePosPixel() const
VclPtr< ListBox > mpListBox
Definition: tabctrl.cxx:86
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:941
std::vector< sal_uInt16 > GetPageIDs() const
Definition: tabctrl.cxx:2182
virtual void KeyInput(const KeyEvent &rKEvt)
Definition: window.cxx:1799
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle, SystemParentData *pSystemParentData)
Definition: window.cxx:935
bool mbUseNativeFocus
Definition: window.h:317
SAL_DLLPRIVATE Size ImplGetItemSize(ImplTabItem *pItem, tools::Long nMaxWidth)
Definition: tabctrl.cxx:227
bool IsModifierChanged() const
Definition: event.hxx:141
void SetPageName(sal_uInt16 nPageId, const OString &rName) const
Definition: tabctrl.cxx:1985
tools::Long A() const
#define TAB_PAGE_NOTFOUND
Definition: tabctrl.hxx:39
void InsertItem(sal_uInt16 nItemId, const OUString &rStr, MenuItemBits nItemBits=MenuItemBits::NONE, const OString &rIdent=OString(), sal_uInt16 nPos=MENU_APPEND)
Definition: menu.cxx:421
#define TAB_BORDER_LEFT
Definition: tabctrl.hxx:46
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:54
tools::Rectangle maRect
Definition: tabctrl.cxx:59
bool IsShift() const
Definition: keycod.hxx:56
virtual ~TabControl() override
Definition: tabctrl.cxx:196
void setAllocation(const Size &rAllocation)
Definition: tabctrl.cxx:1257
bool IsMouseOver() const
Definition: mouse.cxx:606
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: tabctrl.cxx:201
WindowType
Definition: ctrl.hxx:33
OString maTabName
Definition: tabctrl.cxx:58
bool IsSynthetic() const
Definition: event.hxx:139
virtual void GetFocus()
Definition: window.cxx:1835
bool mbNoFocusRects
Definition: svdata.hxx:320
#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:2100
virtual void FillLayoutData() const override
Definition: tabctrl.cxx:2068
void SetFont(const vcl::Font &rNewFont)
tools::Rectangle GetTabBounds(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:2075
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: tabctrl.cxx:1044
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:319
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:1102
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: text.cxx:903
#define SAL_INFO(area, stream)
void EnableChildTransparentMode(bool bEnable=true)
Definition: window2.cxx:1022
bool IsLeft() const
Definition: event.hxx:146
virtual void ImplActivateTabPage(bool bNext)
Definition: tabctrl.cxx:734
sal_uInt16 GetPageId(sal_uInt16 nPos) const
Definition: tabctrl.cxx:1771
const Color & GetTabHighlightTextColor() const
tools::Long AdjustWidth(tools::Long n)
Definition: image.hxx:39
bool IsMod1() const
Definition: keycod.hxx:58
static VclPtr< reference_type > Create(Arg &&...arg)
A construction helper for VclPtr.
Definition: vclptr.hxx:127
tools::Long Height() const
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect)
Definition: paint.cxx:1019
static int m_nOverlap
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
void RemovePage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1674
const Point & GetPosPixel() const
Definition: event.hxx:120
std::unordered_map< int, int > maLayoutLineToPageId
Definition: tabctrl.cxx:83
tools::Long AdjustHeight(tools::Long n)
IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl, ListBox &, void)
Definition: tabctrl.cxx:1026
WinBits const WB_TABSTOP
#define TAB_TABOFFSET_X
Definition: tabctrl.hxx:43
#define TAB_BORDER_TOP
Definition: tabctrl.hxx:47
void setHeight(tools::Long nHeight)
tools::Long GetHeight() const
void ImplInitSettings()
Definition: ctrl.cxx:428
static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
Definition: tabctrl.cxx:371
void SetTabPage(sal_uInt16 nPageId, TabPage *pPage)
Definition: tabctrl.cxx:1871
tools::Long B() const
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
bool IsEnabled() const
Definition: window2.cxx:1122
bool m_bVisible
the tab / page can be visible
Definition: tabctrl.cxx:63
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
const Color & GetTabRolloverTextColor() const
#define TAB_OFFSET
Definition: tabctrl.hxx:42
bool m_bEnabled
the tab / page is selectable
Definition: tabctrl.cxx:62
WinBits GetStyle() const
Definition: window2.cxx:953
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
Point OutputToScreenPixel(const Point &rPos) const
Definition: window.cxx:2804
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
WinBits const WB_GROUP
Point GetLastPointerPosPixel()
Definition: mouse.cxx:562
#define TAB_PAGERECT
Definition: tabctrl.cxx:90
TabControl(vcl::Window *pParent, WinBits nStyle=WB_STDTABCONTROL)
Definition: tabctrl.cxx:189
virtual void Command(const CommandEvent &rCEvt)
Definition: window.cxx:1917
bool IsReallyVisible() const
Definition: window2.cxx:1107
static OUString GetNonMnemonicString(const OUString &rStr, sal_Int32 &rMnemonicPos)
Definition: text.cxx:2229
void InsertPage(sal_uInt16 nPageId, const OUString &rText, sal_uInt16 nPos=TAB_APPEND)
Definition: tabctrl.cxx:1624
WinBits const WB_STDTABCONTROL
bool HasFocus() const
Definition: window.cxx:2965
void SetItemsOffset(const Point &rOffs)
Definition: tabctrl.cxx:2086
virtual void RequestHelp(const HelpEvent &rHEvt)
Definition: window.cxx:1863
The child windows are not invalidated.
sal_Int32 nState
const Color & GetTabTextColor() const
WinBits const WB_NOTABSTOP
#define TAB_EXTRASPACE_X
Definition: tabctrl.hxx:45
aStr
Point TopRight() const
virtual void ActivatePage()
Definition: tabctrl.cxx:1602
tools::Long Right() const
void SetHelpText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1937
void AddChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:317
bool HasLayoutData() const
determines whether we currently have layout data
Definition: ctrl.cxx:90
Point Center() const
sal_uInt16 nPos
sal_uInt16 GetCurPageId() const
Definition: tabctrl.cxx:1841
constexpr sal_uInt16 KEY_TAB
Definition: keycodes.hxx:121
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:157
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: ctrl.cxx:225
#define TAB_APPEND
Definition: tabctrl.hxx:38
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Definition: window.cxx:2181
bool DeactivatePage()
Definition: tabctrl.cxx:1607
virtual void SetSizePixel(const Size &rNewSize) override
Definition: tabctrl.cxx:1327