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