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