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>
29#include <vcl/tabpage.hxx>
30#include <vcl/tabctrl.hxx>
31#include <vcl/toolbox.hxx>
32#include <vcl/layout.hxx>
33#include <vcl/mnemonic.hxx>
35#include <vcl/settings.hxx>
37#include <bitmaps.hlst>
38#include <tools/json_writer.hxx>
39
40#include <svdata.hxx>
41#include <window.h>
42
43#include <deque>
44#include <unordered_map>
45#include <vector>
46
47#define TAB_OFFSET 3
49#define TAB_ITEM_OFFSET_X 10
51#define TAB_ITEM_OFFSET_Y 3
52#define TAB_EXTRASPACE_X 6
53#define TAB_BORDER_LEFT 1
54#define TAB_BORDER_TOP 1
55#define TAB_BORDER_RIGHT 2
56#define TAB_BORDER_BOTTOM 2
57
58class ImplTabItem final
59{
60 sal_uInt16 m_nId;
61
62public:
64 OUString maText;
65 OUString maFormatText;
66 OUString maHelpText;
69 OUString maTabName;
71 sal_uInt16 mnLine;
76
77 ImplTabItem(sal_uInt16 nId);
78
79 sal_uInt16 id() const { return m_nId; }
80};
81
83 : m_nId(nId)
84 , mnLine(0)
85 , mbFullVisible(false)
86 , m_bEnabled(true)
87 , m_bVisible(true)
88{
89}
90
92{
93 std::vector< ImplTabItem > maItemList;
95};
96
97// for the Tab positions
98#define TAB_PAGERECT 0xFFFF
99
101{
102 mbLayoutDirty = true;
103
104 if ( !(nStyle & WB_NOTABSTOP) )
105 nStyle |= WB_TABSTOP;
106 if ( !(nStyle & WB_NOGROUP) )
107 nStyle |= WB_GROUP;
108 if ( !(nStyle & WB_NODIALOGCONTROL) )
109 nStyle |= WB_DIALOGCONTROL;
110
111 Control::ImplInit( pParent, nStyle, nullptr );
112
113 mnLastWidth = 0;
114 mnLastHeight = 0;
115 mnActPageId = 0;
116 mnCurPageId = 0;
117 mbFormat = true;
118 mbShowTabs = true;
119 mbRestoreHelpId = false;
120 mbSmallInvalidate = false;
122 mpTabCtrlData->mpListBox = nullptr;
123
124 ImplInitSettings( true );
125
126 if( nStyle & WB_DROPDOWN )
127 {
129 mpTabCtrlData->mpListBox->SetPosSizePixel( Point( 0, 0 ), Size( 200, 20 ) );
130 mpTabCtrlData->mpListBox->SetSelectHdl( LINK( this, TabControl, ImplListBoxSelectHdl ) );
131 mpTabCtrlData->mpListBox->Show();
132 }
133
134 // if the tabcontrol is drawn (ie filled) by a native widget, make sure all controls will have transparent background
135 // otherwise they will paint with a wrong background
138
139 if (pParent && pParent->IsDialog())
140 pParent->AddChildEventListener( LINK( this, TabControl, ImplWindowEventListener ) );
141}
142
144{
145 return _rStyle.GetTabFont();
146}
147
149{
150 return _rStyle.GetTabTextColor();
151}
152
153void TabControl::ImplInitSettings( bool bBackground )
154{
156
157 if ( !bBackground )
158 return;
159
160 vcl::Window* pParent = GetParent();
161 if ( !IsControlBackground() &&
165
166 {
167 // set transparent mode for NWF tabcontrols to have
168 // the background always cleared properly
171 SetPaintTransparent( true );
174 }
175 else
176 {
179 SetPaintTransparent( false );
180
181 if ( IsControlBackground() )
183 else
184 SetBackground( pParent->GetBackground() );
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
206 // delete TabCtrl data
207 if (mpTabCtrlData)
208 mpTabCtrlData->mpListBox.disposeAndClear();
209 mpTabCtrlData.reset();
211}
212
213ImplTabItem* TabControl::ImplGetItem( sal_uInt16 nId ) const
214{
215 for (auto & item : mpTabCtrlData->maItemList)
216 {
217 if (item.id() == nId)
218 return &item;
219 }
220
221 return nullptr;
222}
223
225{
226 pItem->maFormatText = pItem->maText;
227 Size aSize( GetOutDev()->GetCtrlTextWidth( pItem->maFormatText ), GetTextHeight() );
228 Size aImageSize( 0, 0 );
229 if( !!pItem->maTabImage )
230 {
231 aImageSize = pItem->maTabImage.GetSizePixel();
232 if( !pItem->maFormatText.isEmpty() )
233 aImageSize.AdjustWidth(GetTextHeight()/4 );
234 }
235 aSize.AdjustWidth(aImageSize.Width() );
236 if( aImageSize.Height() > aSize.Height() )
237 aSize.setHeight( aImageSize.Height() );
238
241
242 tools::Rectangle aCtrlRegion( Point( 0, 0 ), aSize );
243 tools::Rectangle aBoundingRgn, aContentRgn;
245 aSize.Width() - TAB_ITEM_OFFSET_X * 2,
246 aSize.Height() - TAB_ITEM_OFFSET_Y * 2));
248 ControlState::ENABLED, aControlValue,
249 aBoundingRgn, aContentRgn ) )
250 {
251 return aContentRgn.GetSize();
252 }
253
254 // For languages with short names (e.g. Chinese), because the space is
255 // normally only one pixel per char
256 if ( pItem->maFormatText.getLength() < TAB_EXTRASPACE_X )
257 aSize.AdjustWidth(TAB_EXTRASPACE_X-pItem->maFormatText.getLength() );
258
259 // shorten Text if needed
260 if ( aSize.Width()+4 >= nMaxWidth )
261 {
262 OUString aAppendStr("...");
263 pItem->maFormatText += aAppendStr;
264 do
265 {
266 if (pItem->maFormatText.getLength() > aAppendStr.getLength())
267 pItem->maFormatText = pItem->maFormatText.replaceAt( pItem->maFormatText.getLength()-aAppendStr.getLength()-1, 1, u"" );
268 aSize.setWidth( GetOutDev()->GetCtrlTextWidth( pItem->maFormatText ) );
269 aSize.AdjustWidth(aImageSize.Width() );
271 }
272 while ( (aSize.Width()+4 >= nMaxWidth) && (pItem->maFormatText.getLength() > aAppendStr.getLength()) );
273 if ( aSize.Width()+4 >= nMaxWidth )
274 {
275 pItem->maFormatText = ".";
276 aSize.setWidth( 1 );
277 }
278 }
279
280 if( pItem->maFormatText.isEmpty() )
281 {
282 if( aSize.Height() < aImageSize.Height()+4 ) //leave space for focus rect
283 aSize.setHeight( aImageSize.Height()+4 );
284 }
285
286 return aSize;
287}
288
289// Feel free to move this to some more general place for reuse
290// http://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
291// Mostly based on Alexey Frunze's nifty example at
292// http://stackoverflow.com/questions/9071205/balanced-word-wrap-minimum-raggedness-in-php
294{
295 static std::deque<size_t> GetEndOfLineIndexes(const std::vector<sal_Int32>& rWidthsOf, sal_Int32 nLineWidth)
296 {
297 ++nLineWidth;
298
299 size_t nWidthsCount = rWidthsOf.size();
300 std::vector<sal_Int32> aCosts(nWidthsCount * nWidthsCount);
301
302 // cost function c(i, j) that computes the cost of a line consisting of
303 // the words Word[i] to Word[j]
304 for (size_t i = 0; i < nWidthsCount; ++i)
305 {
306 for (size_t j = 0; j < nWidthsCount; ++j)
307 {
308 if (j >= i)
309 {
310 sal_Int32 c = nLineWidth - (j - i);
311 for (size_t k = i; k <= j; ++k)
312 c -= rWidthsOf[k];
313 c = (c >= 0) ? c * c : SAL_MAX_INT32;
314 aCosts[j * nWidthsCount + i] = c;
315 }
316 else
317 {
318 aCosts[j * nWidthsCount + i] = SAL_MAX_INT32;
319 }
320 }
321 }
322
323 std::vector<sal_Int32> aFunction(nWidthsCount);
324 std::vector<sal_Int32> aWrapPoints(nWidthsCount);
325
326 // f(j) in aFunction[], collect wrap points in aWrapPoints[]
327 for (size_t j = 0; j < nWidthsCount; ++j)
328 {
329 aFunction[j] = aCosts[j * nWidthsCount];
330 if (aFunction[j] == SAL_MAX_INT32)
331 {
332 for (size_t k = 0; k < j; ++k)
333 {
334 sal_Int32 s;
335 if (aFunction[k] == SAL_MAX_INT32 || aCosts[j * nWidthsCount + k + 1] == SAL_MAX_INT32)
336 s = SAL_MAX_INT32;
337 else
338 s = aFunction[k] + aCosts[j * nWidthsCount + k + 1];
339 if (aFunction[j] > s)
340 {
341 aFunction[j] = s;
342 aWrapPoints[j] = k + 1;
343 }
344 }
345 }
346 }
347
348 std::deque<size_t> aSolution;
349
350 // no solution
351 if (aFunction[nWidthsCount - 1] == SAL_MAX_INT32)
352 return aSolution;
353
354 // optimal solution
355 size_t j = nWidthsCount - 1;
356 while (true)
357 {
358 aSolution.push_front(j);
359 if (!aWrapPoints[j])
360 break;
361 j = aWrapPoints[j] - 1;
362 }
363
364 return aSolution;
365 }
366};
367
368static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
369{
370 if (!ImplGetSVData()->maNWFData.mbCenteredTabs)
371 return;
372
373 int nRightSpace = nMaxWidth; // space left on the right by the tabs
374 for (auto const& item : pTabCtrlData->maItemList)
375 {
376 if (!item.m_bVisible)
377 continue;
378 nRightSpace -= item.maRect.GetWidth();
379 }
380 nRightSpace /= 2;
381
382 for (auto& item : pTabCtrlData->maItemList)
383 {
384 if (!item.m_bVisible)
385 continue;
386 item.maRect.AdjustLeft(nRightSpace);
387 item.maRect.AdjustRight(nRightSpace);
388 }
389}
390
392{
393 if ( nWidth <= 0 )
394 return false;
395 if ( mpTabCtrlData->maItemList.empty() )
396 return false;
397
398 tools::Long nMaxWidth = nWidth;
399
400 const tools::Long nOffsetX = 2;
401 const tools::Long nOffsetY = 2;
402
403 //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
404 //of ugly bare tabs on lines of their own
405
406 //collect widths
407 std::vector<sal_Int32> aWidths;
408 for (auto & item : mpTabCtrlData->maItemList)
409 {
410 if (!item.m_bVisible)
411 continue;
412 aWidths.push_back(ImplGetItemSize(&item, nMaxWidth).Width());
413 }
414
415 //aBreakIndexes will contain the indexes of the last tab on each row
416 std::deque<size_t> aBreakIndexes(MinimumRaggednessWrap::GetEndOfLineIndexes(aWidths, nMaxWidth - nOffsetX - 2));
417
418 tools::Long nX = nOffsetX;
419 tools::Long nY = nOffsetY;
420
421 sal_uInt16 nLines = 0;
422 sal_uInt16 nCurLine = 0;
423
424 tools::Long nLineWidthAry[100];
425 sal_uInt16 nLinePosAry[101];
426 nLineWidthAry[0] = 0;
427 nLinePosAry[0] = 0;
428
429 size_t nIndex = 0;
430
431 for (auto & item : mpTabCtrlData->maItemList)
432 {
433 if (!item.m_bVisible)
434 continue;
435
436 Size aSize = ImplGetItemSize( &item, nMaxWidth );
437
438 bool bNewLine = false;
439 if (!aBreakIndexes.empty() && nIndex > aBreakIndexes.front())
440 {
441 aBreakIndexes.pop_front();
442 bNewLine = true;
443 }
444
445 if ( bNewLine && (nWidth > 2+nOffsetX) )
446 {
447 if ( nLines == 99 )
448 break;
449
450 nX = nOffsetX;
451 nY += aSize.Height();
452 nLines++;
453 nLineWidthAry[nLines] = 0;
454 nLinePosAry[nLines] = nIndex;
455 }
456
457 tools::Rectangle aNewRect( Point( nX, nY ), aSize );
458 if ( mbSmallInvalidate && (item.maRect != aNewRect) )
459 mbSmallInvalidate = false;
460 item.maRect = aNewRect;
461 item.mnLine = nLines;
462 item.mbFullVisible = true;
463
464 nLineWidthAry[nLines] += aSize.Width();
465 nX += aSize.Width();
466
467 if (item.id() == mnCurPageId)
468 nCurLine = nLines;
469
470 ++nIndex;
471 }
472
473 if (nLines) // two or more lines
474 {
475 tools::Long nLineHeightAry[100];
476 tools::Long nIH = 0;
477 for (const auto& item : mpTabCtrlData->maItemList)
478 {
479 if (!item.m_bVisible)
480 continue;
481 nIH = item.maRect.Bottom() - 1;
482 break;
483 }
484
485 for ( sal_uInt16 i = 0; i < nLines+1; i++ )
486 {
487 if ( i <= nCurLine )
488 nLineHeightAry[i] = nIH*(nLines-(nCurLine-i));
489 else
490 nLineHeightAry[i] = nIH*(i-nCurLine-1);
491 }
492
493 nLinePosAry[nLines+1] = static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
494
495 tools::Long nDX = 0;
496 tools::Long nModDX = 0;
497 tools::Long nIDX = 0;
498
499 sal_uInt16 i = 0;
500 sal_uInt16 n = 0;
501
502 for (auto & item : mpTabCtrlData->maItemList)
503 {
504 if (!item.m_bVisible)
505 continue;
506
507 if ( i == nLinePosAry[n] )
508 {
509 if ( n == nLines+1 )
510 break;
511
512 nIDX = 0;
513 if( nLinePosAry[n+1]-i > 0 )
514 {
515 nDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) / ( nLinePosAry[n+1] - i );
516 nModDX = ( nWidth - nOffsetX - nLineWidthAry[n] ) % ( nLinePosAry[n+1] - i );
517 }
518 else
519 {
520 // FIXME: this is a case of tabctrl way too small
521 nDX = 0;
522 nModDX = 0;
523 }
524 n++;
525 }
526
527 item.maRect.AdjustLeft(nIDX );
528 item.maRect.AdjustRight(nIDX + nDX );
529 item.maRect.SetTop( nLineHeightAry[n-1] );
530 item.maRect.SetBottom(nLineHeightAry[n-1] + nIH - 1);
531 nIDX += nDX;
532
533 if ( nModDX )
534 {
535 nIDX++;
536 item.maRect.AdjustRight( 1 );
537 nModDX--;
538 }
539
540 i++;
541 }
542 }
543 else // only one line
544 lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
545
546 return true;
547}
548
550{
552 if ( nWidth < 0 )
553 nWidth = aWinSize.Width();
554 if ( nHeight < 0 )
555 nHeight = aWinSize.Height();
556
557 if ( mpTabCtrlData->maItemList.empty() )
558 {
559 tools::Long nW = nWidth-TAB_OFFSET*2;
560 tools::Long nH = nHeight-TAB_OFFSET*2;
561 return (nW > 0 && nH > 0)
564 }
565
566 if ( nItemPos == TAB_PAGERECT )
567 {
568 sal_uInt16 nLastPos;
569 if ( mnCurPageId )
570 nLastPos = GetPagePos( mnCurPageId );
571 else
572 nLastPos = 0;
573
574 tools::Rectangle aRect = ImplGetTabRect( nLastPos, nWidth, nHeight );
575 if (aRect.IsEmpty())
576 return aRect;
577
578 // with show-tabs of true (the usual) the page rect is from under the
579 // visible tab to the bottom of the TabControl, otherwise it extends
580 // from the top of the TabControl
581 tools::Long nTabBottom = mbShowTabs ? aRect.Bottom() : 0;
582
583 tools::Long nW = nWidth-TAB_OFFSET*2;
584 tools::Long nH = nHeight - nTabBottom - TAB_OFFSET*2;
585 return (nW > 0 && nH > 0)
586 ? tools::Rectangle( Point( TAB_OFFSET, nTabBottom + TAB_OFFSET ), Size( nW, nH ) )
588 }
589
590 ImplTabItem* const pItem = (nItemPos < mpTabCtrlData->maItemList.size())
591 ? &mpTabCtrlData->maItemList[nItemPos] : nullptr;
592 return ImplGetTabRect(pItem, nWidth, nHeight);
593}
594
596{
597 if ((nWidth <= 1) || (nHeight <= 0) || !pItem || !pItem->m_bVisible)
598 return tools::Rectangle();
599
600 nWidth -= 1;
601
602 if ( mbFormat || (mnLastWidth != nWidth) || (mnLastHeight != nHeight) )
603 {
604 vcl::Font aFont( GetFont() );
605 aFont.SetTransparent( true );
606 SetFont( aFont );
607
608 bool bRet = ImplPlaceTabs( nWidth );
609 if ( !bRet )
610 return tools::Rectangle();
611
612 mnLastWidth = nWidth;
613 mnLastHeight = nHeight;
614 mbFormat = false;
615 }
616
617 return pItem->maRect;
618}
619
620void TabControl::ImplChangeTabPage( sal_uInt16 nId, sal_uInt16 nOldId )
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 );
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({});
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 )
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
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 tools::Long nTextHeight = GetTextHeight();
760 tools::Long nTextWidth = GetOutDev()->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 tools::Long nXPos = aRect.Left()+((aTabSize.Width()-nTextWidth-aImageSize.Width())/2)-nOff-1;
787 tools::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
799void 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 tools::Long nLeftBottom = aRect.Bottom();
808 tools::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;
826 if (!ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise)
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.Contains(aLeftTestPos))
837 bLeftBorder = false;
838 aRightTestPos.AdjustX(2 );
839 if (rCurRect.Contains(aRightTestPos))
840 bRightBorder = false;
841 }
842 else
843 {
844 if (rCurRect.Contains(aLeftTestPos))
845 nLeftBottom -= 2;
846 if (rCurRect.Contains(aRightTestPos))
847 nRightBottom -= 2;
848 }
849 }
850
852
853 if (pItem->id() == mnCurPageId)
854 {
856 // only the selected item can be focused
857 if (HasFocus())
859 }
860 if (IsEnabled())
863 {
865 for (auto const& item : mpTabCtrlData->maItemList)
866 if ((&item != pItem) && item.m_bVisible && item.maRect.Contains(GetPointerPosPixel()))
867 {
868 nState &= ~ControlState::ROLLOVER; // avoid multiple highlighted tabs
869 break;
870 }
872 }
873
875 if ( bNativeOK )
876 {
878 pItem->maRect.Top() + TAB_ITEM_OFFSET_Y,
879 pItem->maRect.Right() - TAB_ITEM_OFFSET_X,
880 pItem->maRect.Bottom() - TAB_ITEM_OFFSET_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 );
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 tools::Long nTextHeight = rRenderContext.GetTextHeight();
950 tools::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 tools::Long nXPos = aRect.Left() + ((aTabSize.Width() - nTextWidth - aImageSize.Width()) / 2) - nOff - nOff3;
958 tools::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());
967 aColor = rStyleSettings.GetTabHighlightTextColor();
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
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
1024IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl, ListBox&, void)
1025{
1026 SelectTabPage( GetPageId( mpTabCtrlData->mpListBox->GetSelectedEntryPos() ) );
1027}
1028
1029IMPL_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
1052void 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
1071static 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
1081void 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 = mbShowTabs && rRenderContext.IsNativeControlSupported(ControlType::TabPane, ControlPart::TabPaneWithHeader);
1128 tools::Rectangle aHeaderRect(aRect.Left(), 0, aRect.Right(), aRect.Top());
1129
1130 if (mpTabCtrlData->maItemList.size())
1131 {
1132 tools::Long nLeft = LONG_MAX;
1133 tools::Long nRight = 0;
1134 for (const auto &item : mpTabCtrlData->maItemList)
1135 {
1136 if (!item.m_bVisible)
1137 continue;
1138 nRight = std::max(nRight, item.maRect.Right());
1139 nLeft = std::min(nLeft, item.maRect.Left());
1140 }
1141 aHeaderRect.SetLeft(nLeft);
1142 aHeaderRect.SetRight(nRight);
1143 }
1144
1145 if (bPaneWithHeader)
1146 aRect.SetTop(0);
1147
1148 const TabPaneValue aTabPaneValue(aHeaderRect, pCurItem ? pCurItem->maRect : tools::Rectangle());
1149
1151 if (!IsEnabled())
1152 nState &= ~ControlState::ENABLED;
1153 if (HasFocus())
1155
1156 if (lcl_canPaint(rRenderContext, rRect, aRect))
1158 aRect, nState, aTabPaneValue, OUString());
1159
1160 if (!bPaneWithHeader && rRenderContext.IsNativeControlSupported(ControlType::TabHeader, ControlPart::Entire)
1161 && lcl_canPaint(rRenderContext, rRect, aHeaderRect))
1163 aHeaderRect, nState, aTabPaneValue, OUString());
1164 }
1165 else
1166 {
1167 tools::Long nTopOff = 1;
1168 if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1169 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
1170 else
1171 rRenderContext.SetLineColor(COL_BLACK);
1172 if (mbShowTabs && pCurItem && !pCurItem->maRect.IsEmpty())
1173 {
1174 aCurRect = pCurItem->maRect;
1175 rRenderContext.DrawLine(aRect.TopLeft(), Point(aCurRect.Left() - 2, aRect.Top()));
1176 if (aCurRect.Right() + 1 < aRect.Right())
1177 {
1178 rRenderContext.DrawLine(Point(aCurRect.Right(), aRect.Top()), aRect.TopRight());
1179 }
1180 else
1181 {
1182 nTopOff = 0;
1183 }
1184 }
1185 else
1186 rRenderContext.DrawLine(aRect.TopLeft(), aRect.TopRight());
1187
1188 rRenderContext.DrawLine(aRect.TopLeft(), aRect.BottomLeft());
1189
1190 if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
1191 {
1192 // if we have not tab page the bottom line of the tab page
1193 // directly touches the tab items, so choose a color that fits seamlessly
1194 if (bNoTabPage)
1195 rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1196 else
1197 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
1198 rRenderContext.DrawLine(Point(1, aRect.Bottom() - 1), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1199 rRenderContext.DrawLine(Point(aRect.Right() - 1, aRect.Top() + nTopOff), Point(aRect.Right() - 1, aRect.Bottom() - 1));
1200 if (bNoTabPage)
1201 rRenderContext.SetLineColor(rStyleSettings.GetDialogColor());
1202 else
1203 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
1204 rRenderContext.DrawLine(Point(0, aRect.Bottom()), Point(aRect.Right(), aRect.Bottom()));
1205 rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top() + nTopOff), Point(aRect.Right(), aRect.Bottom()));
1206 }
1207 else
1208 {
1209 rRenderContext.DrawLine(aRect.TopRight(), aRect.BottomRight());
1210 rRenderContext.DrawLine(aRect.BottomLeft(), aRect.BottomRight());
1211 }
1212 }
1213
1214 if (mbShowTabs && !mpTabCtrlData->maItemList.empty() && mpTabCtrlData->mpListBox == nullptr)
1215 {
1216 // Some native toolkits (GTK+) draw tabs right-to-left, with an
1217 // overlap between adjacent tabs
1218 bool bDrawTabsRTL = rRenderContext.IsNativeControlSupported(ControlType::TabItem, ControlPart::TabsDrawRtl);
1219 ImplTabItem* pFirstTab = nullptr;
1220 ImplTabItem* pLastTab = nullptr;
1221 size_t idx;
1222
1223 // Even though there is a tab overlap with GTK+, the first tab is not
1224 // overlapped on the left side. Other toolkits ignore this option.
1225 if (bDrawTabsRTL)
1226 {
1227 pFirstTab = mpTabCtrlData->maItemList.data();
1228 pLastTab = pFirstTab + mpTabCtrlData->maItemList.size() - 1;
1229 idx = mpTabCtrlData->maItemList.size() - 1;
1230 }
1231 else
1232 {
1233 pLastTab = mpTabCtrlData->maItemList.data();
1234 pFirstTab = pLastTab + mpTabCtrlData->maItemList.size() - 1;
1235 idx = 0;
1236 }
1237
1238 while (idx < mpTabCtrlData->maItemList.size())
1239 {
1240 ImplTabItem* pItem = &mpTabCtrlData->maItemList[idx];
1241
1242 if (pItem != pCurItem && pItem->m_bVisible && lcl_canPaint(rRenderContext, rRect, pItem->maRect))
1243 ImplDrawItem(rRenderContext, pItem, aCurRect, pItem == pFirstTab, pItem == pLastTab);
1244
1245 if (bDrawTabsRTL)
1246 idx--;
1247 else
1248 idx++;
1249 }
1250
1251 if (pCurItem && lcl_canPaint(rRenderContext, rRect, pCurItem->maRect))
1252 ImplDrawItem(rRenderContext, pCurItem, aCurRect, pCurItem == pFirstTab, pCurItem == pLastTab);
1253 }
1254
1255 if (HasFocus())
1256 ImplShowFocus();
1257
1258 mbSmallInvalidate = true;
1259}
1260
1261void TabControl::setAllocation(const Size &rAllocation)
1262{
1263 if ( !IsReallyShown() )
1264 return;
1265
1266 if( mpTabCtrlData->mpListBox )
1267 {
1268 // get the listbox' preferred size
1269 Size aTabCtrlSize( GetSizePixel() );
1270 tools::Long nPrefWidth = mpTabCtrlData->mpListBox->get_preferred_size().Width();
1271 if( nPrefWidth > aTabCtrlSize.Width() )
1272 nPrefWidth = aTabCtrlSize.Width();
1273 Size aNewSize( nPrefWidth, LogicToPixel( Size( 12, 12 ), MapMode( MapUnit::MapAppFont ) ).Height() );
1274 Point aNewPos( (aTabCtrlSize.Width() - nPrefWidth) / 2, 0 );
1275 mpTabCtrlData->mpListBox->SetPosSizePixel( aNewPos, aNewSize );
1276 }
1277
1278 mbFormat = true;
1279
1280 // resize/position active TabPage
1281 bool bTabPage = ImplPosCurTabPage();
1282
1283 // check what needs to be invalidated
1284 Size aNewSize = rAllocation;
1285 tools::Long nNewWidth = aNewSize.Width();
1286 for (auto const& item : mpTabCtrlData->maItemList)
1287 {
1288 if (!item.m_bVisible)
1289 continue;
1290 if (!item.mbFullVisible || (item.maRect.Right()-2 >= nNewWidth))
1291 {
1292 mbSmallInvalidate = false;
1293 break;
1294 }
1295 }
1296
1297 if ( mbSmallInvalidate )
1298 {
1304 if ( bTabPage )
1306 else
1307 Invalidate( aRect );
1308
1309 }
1310 else
1311 {
1312 if ( bTabPage )
1314 else
1315 Invalidate();
1316 }
1317
1318 mbLayoutDirty = false;
1319}
1320
1321void TabControl::SetPosSizePixel(const Point& rNewPos, const Size& rNewSize)
1322{
1323 Window::SetPosSizePixel(rNewPos, rNewSize);
1324 //if size changed, TabControl::Resize got called already
1325 if (mbLayoutDirty)
1326 setAllocation(rNewSize);
1327}
1328
1329void TabControl::SetSizePixel(const Size& rNewSize)
1330{
1331 Window::SetSizePixel(rNewSize);
1332 //if size changed, TabControl::Resize got called already
1333 if (mbLayoutDirty)
1334 setAllocation(rNewSize);
1335}
1336
1338{
1339 Window::SetPosPixel(rPos);
1340 if (mbLayoutDirty)
1342}
1343
1345{
1347}
1348
1350{
1351 if( ! mpTabCtrlData->mpListBox )
1352 {
1353 if (mbShowTabs)
1354 {
1355 ImplShowFocus();
1357 }
1358 else
1359 {
1360 // no tabs, focus first thing in current page
1362 if (pItem && pItem->mpTabPage)
1363 {
1365 if ( pFirstChild )
1367 }
1368 }
1369 }
1370 else
1371 {
1372 if( mpTabCtrlData->mpListBox->IsReallyVisible() )
1373 mpTabCtrlData->mpListBox->GrabFocus();
1374 }
1375
1377}
1378
1380{
1381 if( mpTabCtrlData && ! mpTabCtrlData->mpListBox )
1382 HideFocus();
1384}
1385
1387{
1388 sal_uInt16 nItemId = rHEvt.KeyboardActivated() ? mnCurPageId : GetPageId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
1389
1390 if ( nItemId )
1391 {
1392 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1393 {
1394 OUString aStr = GetHelpText( nItemId );
1395 if ( !aStr.isEmpty() )
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 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
1405 return;
1406 }
1407 }
1408
1409 // for Quick or Ballon Help, we show the text, if it is cut
1411 {
1412 ImplTabItem* pItem = ImplGetItem( nItemId );
1413 const OUString& rStr = pItem->maText;
1414 if ( rStr != pItem->maFormatText )
1415 {
1416 tools::Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1417 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1418 aItemRect.SetLeft( aPt.X() );
1419 aItemRect.SetTop( aPt.Y() );
1420 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1421 aItemRect.SetRight( aPt.X() );
1422 aItemRect.SetBottom( aPt.Y() );
1423 if ( !rStr.isEmpty() )
1424 {
1425 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
1426 Help::ShowBalloon( this, aItemRect.Center(), aItemRect, rStr );
1427 else
1428 Help::ShowQuickHelp( this, aItemRect, rStr );
1429 return;
1430 }
1431 }
1432 }
1433
1434 if ( rHEvt.GetMode() & HelpEventMode::QUICK )
1435 {
1436 ImplTabItem* pItem = ImplGetItem( nItemId );
1437 const OUString& rHelpText = pItem->maHelpText;
1438 if (!rHelpText.isEmpty())
1439 {
1440 tools::Rectangle aItemRect = ImplGetTabRect( GetPagePos( nItemId ) );
1441 Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
1442 aItemRect.SetLeft( aPt.X() );
1443 aItemRect.SetTop( aPt.Y() );
1444 aPt = OutputToScreenPixel( aItemRect.BottomRight() );
1445 aItemRect.SetRight( aPt.X() );
1446 aItemRect.SetBottom( aPt.Y() );
1447 Help::ShowQuickHelp( this, aItemRect, rHelpText );
1448 return;
1449 }
1450 }
1451 }
1452
1453 Control::RequestHelp( rHEvt );
1454}
1455
1457{
1458 if( (mpTabCtrlData->mpListBox == nullptr) && (rCEvt.GetCommand() == CommandEventId::ContextMenu) && (GetPageCount() > 1) )
1459 {
1460 Point aMenuPos;
1461 bool bMenu;
1462 if ( rCEvt.IsMouseEvent() )
1463 {
1464 aMenuPos = rCEvt.GetMousePosPixel();
1465 bMenu = GetPageId( aMenuPos ) != 0;
1466 }
1467 else
1468 {
1469 aMenuPos = ImplGetTabRect( GetPagePos( mnCurPageId ) ).Center();
1470 bMenu = true;
1471 }
1472
1473 if ( bMenu )
1474 {
1476 for (auto const& item : mpTabCtrlData->maItemList)
1477 {
1478 aMenu->InsertItem(item.id(), item.maText, MenuItemBits::CHECKABLE | MenuItemBits::RADIOCHECK);
1479 if (item.id() == mnCurPageId)
1480 aMenu->CheckItem(item.id());
1481 aMenu->SetHelpId(item.id(), {});
1482 }
1483
1484 sal_uInt16 nId = aMenu->Execute( this, aMenuPos );
1485 if ( nId && (nId != mnCurPageId) )
1486 SelectTabPage( nId );
1487 return;
1488 }
1489 }
1490
1491 Control::Command( rCEvt );
1492}
1493
1495{
1497
1499 {
1501 if( mpTabCtrlData->mpListBox )
1502 Resize();
1503 }
1504 else if ( nType == StateChangedType::UpdateMode )
1505 {
1506 if ( IsUpdateMode() )
1507 Invalidate();
1508 }
1509 else if ( (nType == StateChangedType::Zoom) ||
1511 {
1512 ImplInitSettings( false );
1513 Invalidate();
1514 }
1516 {
1517 ImplInitSettings( false );
1518 Invalidate();
1519 }
1521 {
1522 ImplInitSettings( true );
1523 Invalidate();
1524 }
1525}
1526
1528{
1529 Control::DataChanged( rDCEvt );
1530
1531 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1533 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1534 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1535 {
1536 ImplInitSettings( true );
1537 Invalidate();
1538 }
1539}
1540
1542{
1543 ImplTabItem* pFoundItem = nullptr;
1544 int nFound = 0;
1545 for (auto & item : mpTabCtrlData->maItemList)
1546 {
1547 if (item.m_bVisible && item.maRect.Contains(rPt))
1548 {
1549 nFound++;
1550 pFoundItem = &item;
1551 }
1552 }
1553
1554 // assure that only one tab is highlighted at a time
1555 assert(nFound <= 1);
1556 return nFound == 1 ? pFoundItem : nullptr;
1557}
1558
1560{
1561 if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
1562 {
1563 const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
1564 if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1565 {
1566 // trigger redraw if mouse over state has changed
1568 {
1571 if ((pItem != pLastItem) || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow())
1572 {
1573 vcl::Region aClipRgn;
1574 if (pLastItem)
1575 {
1576 // allow for slightly bigger tabitems
1577 // as used by gtk
1578 // TODO: query for the correct sizes
1579 tools::Rectangle aRect(pLastItem->maRect);
1580 aRect.AdjustLeft( -2 );
1581 aRect.AdjustRight(2 );
1582 aRect.AdjustTop( -3 );
1583 aClipRgn.Union( aRect );
1584 }
1585
1586 if (pItem)
1587 {
1588 // allow for slightly bigger tabitems
1589 // as used by gtk
1590 // TODO: query for the correct sizes
1591 tools::Rectangle aRect(pItem->maRect);
1592 aRect.AdjustLeft( -2 );
1593 aRect.AdjustRight(2 );
1594 aRect.AdjustTop( -3 );
1595 aClipRgn.Union( aRect );
1596 }
1597
1598 if( !aClipRgn.IsEmpty() )
1599 Invalidate( aClipRgn );
1600 }
1601 }
1602 }
1603 }
1604
1605 return Control::PreNotify(rNEvt);
1606}
1607
1609{
1610 bool bRet = false;
1611
1612 if ( rNEvt.GetType() == NotifyEventType::KEYINPUT )
1613 bRet = ImplHandleKeyEvent( *rNEvt.GetKeyEvent() );
1614
1615 return bRet || Control::EventNotify( rNEvt );
1616}
1617
1619{
1620 maActivateHdl.Call( this );
1621}
1622
1624{
1625 return !maDeactivateHdl.IsSet() || maDeactivateHdl.Call( this );
1626}
1627
1629{
1630 Size aNewSize( rSize );
1631 aNewSize.AdjustWidth(TAB_OFFSET*2 );
1633 aNewSize.Width(), aNewSize.Height() );
1634 aNewSize.AdjustHeight(aRect.Top()+TAB_OFFSET );
1635 Window::SetOutputSizePixel( aNewSize );
1636}
1637
1638void TabControl::InsertPage( sal_uInt16 nPageId, const OUString& rText,
1639 sal_uInt16 nPos )
1640{
1641 SAL_WARN_IF( !nPageId, "vcl", "TabControl::InsertPage(): PageId == 0" );
1643 "TabControl::InsertPage(): PageId already exists" );
1644
1645 // insert new page item
1646 ImplTabItem* pItem = nullptr;
1647 if( nPos == TAB_APPEND || size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1648 {
1649 mpTabCtrlData->maItemList.emplace_back(nPageId);
1650 pItem = &mpTabCtrlData->maItemList.back();
1651 if( mpTabCtrlData->mpListBox )
1652 mpTabCtrlData->mpListBox->InsertEntry( rText );
1653 }
1654 else
1655 {
1656 std::vector< ImplTabItem >::iterator new_it =
1657 mpTabCtrlData->maItemList.emplace(mpTabCtrlData->maItemList.begin() + nPos, nPageId);
1658 pItem = &(*new_it);
1659 if( mpTabCtrlData->mpListBox )
1660 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos);
1661 }
1662 if( mpTabCtrlData->mpListBox )
1663 {
1664 if( ! mnCurPageId )
1665 mpTabCtrlData->mpListBox->SelectEntryPos( 0 );
1666 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1667 }
1668
1669 // set current page id
1670 if ( !mnCurPageId )
1672
1673 // init new page item
1674 pItem->maText = rText;
1675 pItem->mbFullVisible = false;
1676
1677 mbFormat = true;
1678 if ( IsUpdateMode() )
1679 Invalidate();
1680
1681 if( mpTabCtrlData->mpListBox ) // reposition/resize listbox
1682 Resize();
1683
1684 CallEventListeners( VclEventId::TabpageInserted, reinterpret_cast<void*>(nPageId) );
1685}
1686
1687void TabControl::RemovePage( sal_uInt16 nPageId )
1688{
1689 sal_uInt16 nPos = GetPagePos( nPageId );
1690
1691 // does the item exist ?
1692 if ( nPos == TAB_PAGE_NOTFOUND )
1693 return;
1694
1695 //remove page item
1696 std::vector< ImplTabItem >::iterator it = mpTabCtrlData->maItemList.begin() + nPos;
1697 bool bIsCurrentPage = (it->id() == mnCurPageId);
1698 mpTabCtrlData->maItemList.erase( it );
1699 if( mpTabCtrlData->mpListBox )
1700 {
1701 mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1702 mpTabCtrlData->mpListBox->SetDropDownLineCount( mpTabCtrlData->mpListBox->GetEntryCount() );
1703 }
1704
1705 // If current page is removed, then first page gets the current page
1706 if ( bIsCurrentPage )
1707 {
1708 mnCurPageId = 0;
1709
1710 if( ! mpTabCtrlData->maItemList.empty() )
1711 {
1712 // don't do this by simply setting mnCurPageId to pFirstItem->id()
1713 // this leaves a lot of stuff (such trivia as _showing_ the new current page) undone
1714 // instead, call SetCurPageId
1715 // without this, the next (outside) call to SetCurPageId with the id of the first page
1716 // will result in doing nothing (as we assume that nothing changed, then), and the page
1717 // will never be shown.
1718 // 86875 - 05/11/2001 - frank.schoenheit@germany.sun.com
1719
1720 SetCurPageId(mpTabCtrlData->maItemList[0].id());
1721 }
1722 }
1723
1724 mbFormat = true;
1725 if ( IsUpdateMode() )
1726 Invalidate();
1727
1728 CallEventListeners( VclEventId::TabpageRemoved, reinterpret_cast<void*>(nPageId) );
1729}
1730
1731void TabControl::SetPageEnabled( sal_uInt16 i_nPageId, bool i_bEnable )
1732{
1733 ImplTabItem* pItem = ImplGetItem( i_nPageId );
1734
1735 if (!pItem || pItem->m_bEnabled == i_bEnable)
1736 return;
1737
1738 pItem->m_bEnabled = i_bEnable;
1739 if (!pItem->m_bVisible)
1740 return;
1741
1742 mbFormat = true;
1743 if( mpTabCtrlData->mpListBox )
1744 mpTabCtrlData->mpListBox->SetEntryFlags( GetPagePos( i_nPageId ),
1746
1747 // SetCurPageId will change to a valid page
1748 if (pItem->id() == mnCurPageId)
1750 else if ( IsUpdateMode() )
1751 Invalidate();
1752}
1753
1754void TabControl::SetPageVisible( sal_uInt16 nPageId, bool bVisible )
1755{
1756 ImplTabItem* pItem = ImplGetItem( nPageId );
1757 if (!pItem || pItem->m_bVisible == bVisible)
1758 return;
1759
1760 pItem->m_bVisible = bVisible;
1761 if (!bVisible)
1762 {
1763 if (pItem->mbFullVisible)
1764 mbSmallInvalidate = false;
1765 pItem->mbFullVisible = false;
1766 pItem->maRect.SetEmpty();
1767 }
1768 mbFormat = true;
1769
1770 // SetCurPageId will change to a valid page
1771 if (pItem->id() == mnCurPageId)
1773 else if (IsUpdateMode())
1774 Invalidate();
1775}
1776
1778{
1779 return static_cast<sal_uInt16>(mpTabCtrlData->maItemList.size());
1780}
1781
1782sal_uInt16 TabControl::GetPageId( sal_uInt16 nPos ) const
1783{
1784 if( size_t(nPos) < mpTabCtrlData->maItemList.size() )
1785 return mpTabCtrlData->maItemList[nPos].id();
1786 return 0;
1787}
1788
1789sal_uInt16 TabControl::GetPagePos( sal_uInt16 nPageId ) const
1790{
1791 sal_uInt16 nPos = 0;
1792 for (auto const& item : mpTabCtrlData->maItemList)
1793 {
1794 if (item.id() == nPageId)
1795 return nPos;
1796 ++nPos;
1797 }
1798
1799 return TAB_PAGE_NOTFOUND;
1800}
1801
1802sal_uInt16 TabControl::GetPageId( const Point& rPos ) const
1803{
1805 const auto &rList = mpTabCtrlData->maItemList;
1806 const auto it = std::find_if(rList.begin(), rList.end(), [&rPos, &winSize, this](const auto &item) {
1807 return const_cast<TabControl*>(this)->ImplGetTabRect(&item, winSize.Width(), winSize.Height()).Contains(rPos); });
1808 return (it != rList.end()) ? it->id() : 0;
1809}
1810
1811sal_uInt16 TabControl::GetPageId( const OUString& rName ) const
1812{
1813 const auto &rList = mpTabCtrlData->maItemList;
1814 const auto it = std::find_if(rList.begin(), rList.end(), [&rName](const auto &item) {
1815 return item.maTabName == rName; });
1816 return (it != rList.end()) ? it->id() : 0;
1817}
1818
1819void TabControl::SetCurPageId( sal_uInt16 nPageId )
1820{
1821 sal_uInt16 nPos = GetPagePos( nPageId );
1822 while (nPos != TAB_PAGE_NOTFOUND && !mpTabCtrlData->maItemList[nPos].m_bEnabled)
1823 {
1824 nPos++;
1825 if( size_t(nPos) >= mpTabCtrlData->maItemList.size() )
1826 nPos = 0;
1827 if (mpTabCtrlData->maItemList[nPos].id() == nPageId)
1828 break;
1829 }
1830
1831 if( nPos == TAB_PAGE_NOTFOUND )
1832 return;
1833
1834 nPageId = mpTabCtrlData->maItemList[nPos].id();
1835 if ( nPageId == mnCurPageId )
1836 {
1837 if ( mnActPageId )
1839 return;
1840 }
1841
1842 if ( mnActPageId )
1844 else
1845 {
1846 mbFormat = true;
1847 sal_uInt16 nOldId = mnCurPageId;
1849 ImplChangeTabPage( nPageId, nOldId );
1850 }
1851}
1852
1854{
1855 if ( mnActPageId )
1856 return mnActPageId;
1857 else
1858 return mnCurPageId;
1859}
1860
1861void TabControl::SelectTabPage( sal_uInt16 nPageId )
1862{
1863 if ( !nPageId || (nPageId == mnCurPageId) )
1864 return;
1865
1867 if ( DeactivatePage() )
1868 {
1870 ActivatePage();
1871 // Page could have been switched by the Activate handler
1873 mnActPageId = 0;
1875 if( mpTabCtrlData->mpListBox )
1876 mpTabCtrlData->mpListBox->SelectEntryPos( GetPagePos( nPageId ) );
1877 CallEventListeners( VclEventId::TabpageActivate, reinterpret_cast<void*>(nPageId) );
1878 }
1879}
1880
1881void TabControl::SetTabPage( sal_uInt16 nPageId, TabPage* pTabPage )
1882{
1883 ImplTabItem* pItem = ImplGetItem( nPageId );
1884
1885 if ( !pItem || (pItem->mpTabPage.get() == pTabPage) )
1886 return;
1887
1888 if ( pTabPage )
1889 {
1890 if ( IsDefaultSize() )
1891 SetTabPageSizePixel( pTabPage->GetSizePixel() );
1892
1893 // only set here, so that Resize does not reposition TabPage
1894 pItem->mpTabPage = pTabPage;
1895 queue_resize();
1896
1897 if (pItem->id() == mnCurPageId)
1898 ImplChangeTabPage(pItem->id(), 0);
1899 }
1900 else
1901 {
1902 pItem->mpTabPage = nullptr;
1903 queue_resize();
1904 }
1905}
1906
1907TabPage* TabControl::GetTabPage( sal_uInt16 nPageId ) const
1908{
1909 ImplTabItem* pItem = ImplGetItem( nPageId );
1910
1911 if ( pItem )
1912 return pItem->mpTabPage;
1913 else
1914 return nullptr;
1915}
1916
1917void TabControl::SetPageText( sal_uInt16 nPageId, const OUString& rText )
1918{
1919 ImplTabItem* pItem = ImplGetItem( nPageId );
1920
1921 if ( !pItem || pItem->maText == rText )
1922 return;
1923
1924 pItem->maText = rText;
1925 mbFormat = true;
1926 if( mpTabCtrlData->mpListBox )
1927 {
1928 sal_uInt16 nPos = GetPagePos( nPageId );
1929 mpTabCtrlData->mpListBox->RemoveEntry( nPos );
1930 mpTabCtrlData->mpListBox->InsertEntry( rText, nPos );
1931 }
1932 if ( IsUpdateMode() )
1933 Invalidate();
1935}
1936
1937OUString const & TabControl::GetPageText( sal_uInt16 nPageId ) const
1938{
1939 ImplTabItem* pItem = ImplGetItem( nPageId );
1940
1941 assert( pItem );
1942
1943 return pItem->maText;
1944}
1945
1946void TabControl::SetHelpText( sal_uInt16 nPageId, const OUString& rText )
1947{
1948 ImplTabItem* pItem = ImplGetItem( nPageId );
1949
1950 assert( pItem );
1951
1952 pItem->maHelpText = rText;
1953}
1954
1955const OUString& TabControl::GetHelpText( sal_uInt16 nPageId ) const
1956{
1957 ImplTabItem* pItem = ImplGetItem( nPageId );
1958 assert( pItem );
1959 return pItem->maHelpText;
1960}
1961
1962void TabControl::SetAccessibleName(sal_uInt16 nPageId, const OUString& rName)
1963{
1964 ImplTabItem* pItem = ImplGetItem( nPageId );
1965 assert( pItem );
1966 pItem->maAccessibleName = rName;
1967}
1968
1969OUString TabControl::GetAccessibleName( sal_uInt16 nPageId ) const
1970{
1971 ImplTabItem* pItem = ImplGetItem( nPageId );
1972 assert( pItem );
1973 if (!pItem->maAccessibleName.isEmpty())
1974 return pItem->maAccessibleName;
1975 return removeMnemonicFromString(pItem->maText);
1976}
1977
1978void TabControl::SetAccessibleDescription(sal_uInt16 nPageId, const OUString& rDesc)
1979{
1980 ImplTabItem* pItem = ImplGetItem( nPageId );
1981 assert( pItem );
1982 pItem->maAccessibleDescription = rDesc;
1983}
1984
1985OUString TabControl::GetAccessibleDescription( sal_uInt16 nPageId ) const
1986{
1987 ImplTabItem* pItem = ImplGetItem( nPageId );
1988 assert( pItem );
1989 if (!pItem->maAccessibleDescription.isEmpty())
1990 return pItem->maAccessibleDescription;
1991 return pItem->maHelpText;
1992}
1993
1994void TabControl::SetPageName( sal_uInt16 nPageId, const OUString& rName ) const
1995{
1996 ImplTabItem* pItem = ImplGetItem( nPageId );
1997
1998 if ( pItem )
1999 pItem->maTabName = rName;
2000}
2001
2002OUString TabControl::GetPageName( sal_uInt16 nPageId ) const
2003{
2004 ImplTabItem* pItem = ImplGetItem( nPageId );
2005
2006 if (pItem)
2007 return pItem->maTabName;
2008
2009 return {};
2010}
2011
2012void TabControl::SetPageImage( sal_uInt16 i_nPageId, const Image& i_rImage )
2013{
2014 ImplTabItem* pItem = ImplGetItem( i_nPageId );
2015
2016 if ( pItem )
2017 {
2018 pItem->maTabImage = i_rImage;
2019 mbFormat = true;
2020 if ( IsUpdateMode() )
2021 Invalidate();
2022 }
2023}
2024
2026{
2027 tools::Rectangle aRet;
2028
2029 ImplTabItem* pItem = ImplGetItem( nPageId );
2030 if (pItem && pItem->m_bVisible)
2031 aRet = pItem->maRect;
2032
2033 return aRet;
2034}
2035
2036Size TabControl::ImplCalculateRequisition(sal_uInt16& nHeaderHeight) const
2037{
2038 Size aOptimalPageSize(0, 0);
2039
2040 sal_uInt16 nOrigPageId = GetCurPageId();
2041 for (auto const& item : mpTabCtrlData->maItemList)
2042 {
2043 const TabPage *pPage = item.mpTabPage;
2044 //it's a real nuisance if the page is not inserted yet :-(
2045 //We need to force all tabs to exist to get overall optimal size for dialog
2046 if (!pPage)
2047 {
2048 TabControl *pThis = const_cast<TabControl*>(this);
2049 pThis->SetCurPageId(item.id());
2050 pThis->ActivatePage();
2051 pPage = item.mpTabPage;
2052 }
2053
2054 if (!pPage)
2055 continue;
2056
2057 Size aPageSize(VclContainer::getLayoutRequisition(*pPage));
2058
2059 if (aPageSize.Width() > aOptimalPageSize.Width())
2060 aOptimalPageSize.setWidth( aPageSize.Width() );
2061 if (aPageSize.Height() > aOptimalPageSize.Height())
2062 aOptimalPageSize.setHeight( aPageSize.Height() );
2063 }
2064
2065 //fdo#61940 If we were forced to activate pages in order to on-demand
2066 //create them to get their optimal size, then switch back to the original
2067 //page and re-activate it
2068 if (nOrigPageId != GetCurPageId())
2069 {
2070 TabControl *pThis = const_cast<TabControl*>(this);
2071 pThis->SetCurPageId(nOrigPageId);
2072 pThis->ActivatePage();
2073 }
2074
2075 tools::Long nTabLabelsBottom = 0, nTabLabelsRight = 0;
2076 if (mbShowTabs)
2077 {
2078 for (sal_uInt16 nPos(0), sizeList(static_cast <sal_uInt16> (mpTabCtrlData->maItemList.size()));
2079 nPos < sizeList; ++nPos)
2080 {
2081 TabControl* pThis = const_cast<TabControl*>(this);
2082
2083 tools::Rectangle aTabRect = pThis->ImplGetTabRect(nPos, aOptimalPageSize.Width(), LONG_MAX);
2084 if (aTabRect.Bottom() > nTabLabelsBottom)
2085 {
2086 nTabLabelsBottom = aTabRect.Bottom();
2087 nHeaderHeight = nTabLabelsBottom;
2088 }
2089 if (!aTabRect.IsEmpty() && aTabRect.Right() > nTabLabelsRight)
2090 nTabLabelsRight = aTabRect.Right();
2091 }
2092 }
2093
2094 Size aOptimalSize(aOptimalPageSize);
2095 aOptimalSize.AdjustHeight(nTabLabelsBottom );
2096 aOptimalSize.setWidth( std::max(nTabLabelsRight, aOptimalSize.Width()) );
2097
2098 aOptimalSize.AdjustWidth(TAB_OFFSET * 2 );
2099 aOptimalSize.AdjustHeight(TAB_OFFSET * 2 );
2100
2101 return aOptimalSize;
2102}
2103
2105{
2106 sal_uInt16 nHeaderHeight;
2107 return ImplCalculateRequisition(nHeaderHeight);
2108}
2109
2111{
2112 return calculateRequisition();
2113}
2114
2116{
2117 mbLayoutDirty = true;
2118 Window::queue_resize(eReason);
2119}
2120
2121std::vector<sal_uInt16> TabControl::GetPageIDs() const
2122{
2123 std::vector<sal_uInt16> aIDs;
2124 for (auto const& item : mpTabCtrlData->maItemList)
2125 {
2126 aIDs.push_back(item.id());
2127 }
2128
2129 return aIDs;
2130}
2131
2132bool TabControl::set_property(const OUString &rKey, const OUString &rValue)
2133{
2134 if (rKey == "show-tabs")
2135 {
2136 mbShowTabs = toBool(rValue);
2137 queue_resize();
2138 }
2139 else
2140 return Control::set_property(rKey, rValue);
2141 return true;
2142}
2143
2145{
2147}
2148
2150{
2151 rJsonWriter.put("id", get_id());
2152 rJsonWriter.put("type", "tabcontrol");
2153 rJsonWriter.put("selected", GetCurPageId());
2154
2155 {
2156 auto childrenNode = rJsonWriter.startArray("children");
2157 for (auto id : GetPageIDs())
2158 {
2159 TabPage* pChild = GetTabPage(id);
2160
2161 if (pChild)
2162 {
2163 auto childNode = rJsonWriter.startStruct();
2164 pChild->DumpAsPropertyTree(rJsonWriter);
2165
2166 if (!pChild->IsVisible())
2167 rJsonWriter.put("hidden", true);
2168 }
2169 }
2170 }
2171 {
2172 auto tabsNode = rJsonWriter.startArray("tabs");
2173 for(auto id : GetPageIDs())
2174 {
2175 auto tabNode = rJsonWriter.startStruct();
2176 rJsonWriter.put("text", GetPageText(id));
2177 rJsonWriter.put("id", id);
2178 rJsonWriter.put("name", GetPageName(id));
2179 }
2180 }
2181}
2182
2183sal_uInt16 NotebookbarTabControlBase::m_nHeaderHeight = 0;
2184
2185IMPL_LINK_NOARG(NotebookbarTabControlBase, OpenMenu, Button*, void)
2186{
2187 m_aIconClickHdl.Call(static_cast<NotebookBar*>(GetParent()->GetParent()));
2188}
2189
2190NotebookbarTabControlBase::NotebookbarTabControlBase(vcl::Window* pParent)
2191 : TabControl(pParent, WB_STDTABCONTROL)
2192 , bLastContextWasSupported(true)
2193 , eLastContext(vcl::EnumContext::Context::Any)
2194{
2195 m_pOpenMenu = VclPtr<PushButton>::Create( this , WB_CENTER | WB_VCENTER );
2196 m_pOpenMenu->SetClickHdl(LINK(this, NotebookbarTabControlBase, OpenMenu));
2197 m_pOpenMenu->SetModeImage(Image(StockImage::Yes, SV_RESID_BITMAP_NOTEBOOKBAR));
2198 m_pOpenMenu->SetSizePixel(m_pOpenMenu->GetOptimalSize());
2199 m_pOpenMenu->Show();
2200}
2201
2202NotebookbarTabControlBase::~NotebookbarTabControlBase()
2203{
2204 disposeOnce();
2205}
2206
2207void NotebookbarTabControlBase::SetContext( vcl::EnumContext::Context eContext )
2208{
2209 if (eLastContext == eContext)
2210 return;
2211
2212 bool bHandled = false;
2213
2214 TabPage* pPage = GetTabPage(mnCurPageId);
2215 // Try to stay on the current tab (unless the new context has a special tab)
2216 if (pPage && eLastContext != vcl::EnumContext::Context::Any
2217 && pPage->HasContext(vcl::EnumContext::Context::Any) && pPage->IsEnabled())
2218 {
2219 bHandled = true;
2220 }
2221
2222 for (int nChild = 0; nChild < GetPageCount(); ++nChild)
2223 {
2224 sal_uInt16 nPageId = TabControl::GetPageId(nChild);
2225 pPage = GetTabPage(nPageId);
2226
2227 if (!pPage)
2228 continue;
2229
2230 SetPageVisible(nPageId, pPage->HasContext(eContext) || pPage->HasContext(vcl::EnumContext::Context::Any));
2231
2232 if (eContext != vcl::EnumContext::Context::Any
2233 && (!bHandled || !pPage->HasContext(vcl::EnumContext::Context::Any))
2234 && pPage->HasContext(eContext))
2235 {
2236 SetCurPageId(nPageId);
2237 bHandled = true;
2238 bLastContextWasSupported = true;
2239 }
2240
2241 if (!bHandled && bLastContextWasSupported
2242 && pPage->HasContext(vcl::EnumContext::Context::Default))
2243 {
2244 SetCurPageId(nPageId);
2245 }
2246 }
2247
2248 if (!bHandled)
2249 bLastContextWasSupported = false;
2250 eLastContext = eContext;
2251
2252 // tdf#152908 Tabbed compact toolbar does not repaint itself when tabs getting removed
2253 // For unknown reason this is needed by the tabbed compact toolbar for other than gtk
2254 // vcl backends.
2255 Resize();
2256}
2257
2258void NotebookbarTabControlBase::dispose()
2259{
2260 m_pShortcuts.disposeAndClear();
2261 m_pOpenMenu.disposeAndClear();
2263}
2264
2265void NotebookbarTabControlBase::SetToolBox( ToolBox* pToolBox )
2266{
2267 m_pShortcuts.set( pToolBox );
2268}
2269
2270void NotebookbarTabControlBase::SetIconClickHdl( Link<NotebookBar*, void> aHdl )
2271{
2272 m_aIconClickHdl = aHdl;
2273}
2274
2275static bool lcl_isValidPage(const ImplTabItem& rItem, bool& bFound)
2276{
2277 if (rItem.m_bVisible && rItem.m_bEnabled)
2278 bFound = true;
2279 return bFound;
2280}
2281
2282void NotebookbarTabControlBase::ImplActivateTabPage( bool bNext )
2283{
2284 const sal_uInt16 nOldPos = GetPagePos(GetCurPageId());
2285 bool bFound = false;
2286 sal_Int32 nCurPos = nOldPos;
2287
2288 if (bNext)
2289 {
2290 for (nCurPos++; nCurPos < GetPageCount(); nCurPos++)
2291 if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2292 break;
2293 }
2294 else
2295 {
2296 for (nCurPos--; nCurPos >= 0; nCurPos--)
2297 if (lcl_isValidPage(mpTabCtrlData->maItemList[nCurPos], bFound))
2298 break;
2299 }
2300
2301 if (!bFound)
2302 nCurPos = nOldPos;
2303 SelectTabPage( TabControl::GetPageId( nCurPos ) );
2304}
2305
2306sal_uInt16 NotebookbarTabControlBase::GetHeaderHeight()
2307{
2308 return m_nHeaderHeight;
2309}
2310
2311bool NotebookbarTabControlBase::ImplPlaceTabs( tools::Long nWidth )
2312{
2313 if ( nWidth <= 0 )
2314 return false;
2315 if ( mpTabCtrlData->maItemList.empty() )
2316 return false;
2317 if (!m_pOpenMenu || m_pOpenMenu->isDisposed())
2318 return false;
2319
2320 const tools::Long nHamburgerWidth = m_pOpenMenu->GetSizePixel().Width();
2321 tools::Long nMaxWidth = nWidth - nHamburgerWidth;
2322 tools::Long nShortcutsWidth = m_pShortcuts != nullptr ? m_pShortcuts->GetSizePixel().getWidth() + 1 : 0;
2323 tools::Long nFullWidth = nShortcutsWidth;
2324
2325 const tools::Long nOffsetX = 2 + nShortcutsWidth;
2326 const tools::Long nOffsetY = 2;
2327
2328 //fdo#66435 throw Knuth/Tex minimum raggedness algorithm at the problem
2329 //of ugly bare tabs on lines of their own
2330
2331 for (auto & item : mpTabCtrlData->maItemList)
2332 {
2333 tools::Long nTabWidth = 0;
2334 if (item.m_bVisible)
2335 {
2336 nTabWidth = ImplGetItemSize(&item, nMaxWidth).getWidth();
2337 if (!item.maText.isEmpty() && nTabWidth < 100)
2338 nTabWidth = 100;
2339 }
2340 nFullWidth += nTabWidth;
2341 }
2342
2343 tools::Long nX = nOffsetX;
2344 tools::Long nY = nOffsetY;
2345
2346 tools::Long nLineWidthAry[100];
2347 nLineWidthAry[0] = 0;
2348
2349 for (auto & item : mpTabCtrlData->maItemList)
2350 {
2351 if (!item.m_bVisible)
2352 continue;
2353
2354 Size aSize = ImplGetItemSize( &item, nMaxWidth );
2355
2356 // set minimum tab size
2357 if( nFullWidth < nMaxWidth && !item.maText.isEmpty() && aSize.getWidth() < 100)
2358 aSize.setWidth( 100 );
2359
2360 if( !item.maText.isEmpty() && aSize.getHeight() < 28 )
2361 aSize.setHeight( 28 );
2362
2363 tools::Rectangle aNewRect( Point( nX, nY ), aSize );
2364 if ( mbSmallInvalidate && (item.maRect != aNewRect) )
2365 mbSmallInvalidate = false;
2366
2367 item.maRect = aNewRect;
2368 item.mnLine = 0;
2369 item.mbFullVisible = true;
2370
2371 nLineWidthAry[0] += aSize.Width();
2372 nX += aSize.Width();
2373 }
2374
2375 // we always have only one line of tabs
2376 lcl_AdjustSingleLineTabs(nMaxWidth, mpTabCtrlData.get());
2377
2378 // position the shortcutbox
2379 if (m_pShortcuts)
2380 {
2381 tools::Long nPosY = (m_nHeaderHeight - m_pShortcuts->GetSizePixel().getHeight()) / 2;
2382 m_pShortcuts->SetPosPixel(Point(0, nPosY));
2383 }
2384
2385 tools::Long nPosY = (m_nHeaderHeight - m_pOpenMenu->GetSizePixel().getHeight()) / 2;
2386 // position the menu
2387 m_pOpenMenu->SetPosPixel(Point(nWidth - nHamburgerWidth, nPosY));
2388
2389 return true;
2390}
2391
2392Size NotebookbarTabControlBase::calculateRequisition() const
2393{
2394 return TabControl::ImplCalculateRequisition(m_nHeaderHeight);
2395}
2396
2397Control* NotebookbarTabControlBase::GetOpenMenu()
2398{
2399 return m_pOpenMenu;
2400}
2401
2402/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DrawTextFlags
sal_Int32 nLineWidth
sal_uInt16 nPageId
static bool toBool(std::string_view rValue)
Definition: builder.cxx:92
const StyleSettings & GetStyleSettings() const
CommandEventId GetCommand() const
const Point & GetMousePosPixel() const
bool IsMouseEvent() const
Definition: ctrl.hxx:80
tools::Rectangle DrawControlText(OutputDevice &_rTargetDevice, const tools::Rectangle &_rRect, const OUString &_rStr, DrawTextFlags _nStyle, std::vector< tools::Rectangle > *_pVector, OUString *_pDisplayText, const Size *i_pDeviceSize=nullptr) const
draws the given text onto the given device
Definition: ctrl.cxx:428
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: ctrl.cxx:225
virtual void StateChanged(StateChangedType nStateChange) override
Definition: ctrl.cxx:256
void CallEventListeners(VclEventId nEvent, void *pData=nullptr)
Definition: ctrl.cxx:293
void ImplInitSettings()
Definition: ctrl.cxx:423
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects.
Definition: ctrl.cxx:61
DataChangedEventType GetType() const
Definition: event.hxx:362
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
HelpEventMode GetMode() const
Definition: event.hxx:208
bool KeyboardActivated() const
Definition: event.hxx:209
const Point & GetMousePosPixel() const
Definition: event.hxx:207
static void ShowQuickHelp(vcl::Window *pParent, const tools::Rectangle &rScreenRect, const OUString &rHelpText, QuickHelpFlags nStyle=QuickHelpFlags::NONE)
Definition: help.cxx:180
static void ShowBalloon(vcl::Window *pParent, const Point &rScreenPos, const tools::Rectangle &, const OUString &rHelpText)
Definition: help.cxx:157
Definition: image.hxx:40
Size GetSizePixel() const
Definition: Image.cxx:88
sal_uInt16 id() const
Definition: tabctrl.cxx:79
ImplTabItem(sal_uInt16 nId)
Definition: tabctrl.cxx:82
sal_uInt16 mnLine
Definition: tabctrl.cxx:71
OUString maAccessibleName
Definition: tabctrl.cxx:67
bool mbFullVisible
Definition: tabctrl.cxx:72
bool m_bVisible
the tab / page can be visible
Definition: tabctrl.cxx:74
tools::Rectangle maRect
Definition: tabctrl.cxx:70
OUString maText
Definition: tabctrl.cxx:64
VclPtr< TabPage > mpTabPage
Definition: tabctrl.cxx:63
bool m_bEnabled
the tab / page is selectable
Definition: tabctrl.cxx:73
OUString maFormatText
Definition: tabctrl.cxx:65
OUString maHelpText
Definition: tabctrl.cxx:66
Image maTabImage
Definition: tabctrl.cxx:75
OUString maTabName
Definition: tabctrl.cxx:69
OUString maAccessibleDescription
Definition: tabctrl.cxx:68
sal_uInt16 m_nId
Definition: tabctrl.cxx:60
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
A widget used to choose from a list of items and which has no entry.
Definition: lstbox.hxx:83
bool IsEnterWindow() const
Definition: event.hxx:138
bool IsSynthetic() const
Definition: event.hxx:142
bool IsLeaveWindow() const
Definition: event.hxx:140
sal_uInt16 GetButtons() const
Definition: event.hxx:147
const Point & GetPosPixel() const
Definition: event.hxx:123
bool IsModifierChanged() const
Definition: event.hxx:144
bool IsLeft() const
Definition: event.hxx:149
This implements Widget Layout-based notebook-like menu bar.
Definition: notebookbar.hxx:28
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:324
NotifyEventType GetType() const
Definition: event.hxx:308
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:170
virtual vcl::Region GetActiveClipRegion() const
tools::Long GetCtrlTextWidth(const OUString &rStr, const SalLayoutGlyphs *pLayoutCache=nullptr) const
Definition: text.cxx:2290
const vcl::Font & GetFont() const
Definition: outdev.hxx:529
void SetFont(const vcl::Font &rNewFont)
Definition: outdev/font.cxx:56
void DrawLine(const Point &rStartPt, const Point &rEndPt)
Definition: line.cxx:161
void SetLineColor()
Definition: line.cxx:37
void SetTextColor(const Color &rColor)
Definition: text.cxx:716
void DrawPixel(const Point &rPt)
Definition: pixel.cxx:54
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...
const Color & GetTextColor() const
Definition: outdev.hxx:1003
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: text.cxx:897
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.
const AllSettings & GetSettings() const
Definition: outdev.hxx:288
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
constexpr tools::Long Y() const
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
A construction helper for ScopedVclPtr.
Definition: vclptr.hxx:409
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
constexpr tools::Long getWidth() const
void setWidth(tools::Long nWidth)
tools::Long AdjustWidth(tools::Long n)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
const Color & GetDarkShadowColor() const
const Color & GetShadowColor() const
StyleSettingsOptions GetOptions() const
const Color & GetTabRolloverTextColor() const
const Color & GetTabTextColor() const
const vcl::Font & GetTabFont() const
const Color & GetLightColor() const
const Color & GetDialogColor() const
const Color & GetTabHighlightTextColor() const
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
bool mbShowTabs
Definition: tabctrl.hxx:51
sal_uInt16 GetPageCount() const
Definition: tabctrl.cxx:1777
bool mbRestoreHelpId
Definition: tabctrl.hxx:52
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1608
void ActivatePage()
Definition: tabctrl.cxx:1618
virtual Size calculateRequisition() const
Definition: tabctrl.cxx:2104
virtual void RequestHelp(const HelpEvent &rHEvt) override
Definition: tabctrl.cxx:1386
tools::Rectangle GetTabBounds(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:2025
SAL_DLLPRIVATE Size ImplGetItemSize(ImplTabItem *pItem, tools::Long nMaxWidth)
Definition: tabctrl.cxx:224
virtual void GetFocus() override
Definition: tabctrl.cxx:1349
Link< TabControl *, bool > maDeactivateHdl
Definition: tabctrl.hxx:56
void setAllocation(const Size &rAllocation)
Definition: tabctrl.cxx:1261
std::vector< sal_uInt16 > GetPageIDs() const
Definition: tabctrl.cxx:2121
virtual void StateChanged(StateChangedType nType) override
Definition: tabctrl.cxx:1494
virtual const Color & GetCanonicalTextColor(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:148
TabControl(vcl::Window *pParent, WinBits nStyle=WB_STDTABCONTROL)
Definition: tabctrl.cxx:188
sal_uInt16 mnCurPageId
Definition: tabctrl.hxx:49
void SetAccessibleDescription(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1978
void SetTabPage(sal_uInt16 nPageId, TabPage *pPage)
Definition: tabctrl.cxx:1881
virtual ~TabControl() override
Definition: tabctrl.cxx:195
SAL_DLLPRIVATE void ImplChangeTabPage(sal_uInt16 nId, sal_uInt16 nOldId)
Definition: tabctrl.cxx:620
virtual const vcl::Font & GetCanonicalFont(const StyleSettings &_rStyle) const override
Definition: tabctrl.cxx:143
virtual bool set_property(const OUString &rKey, const OUString &rValue) override
Definition: tabctrl.cxx:2132
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
Definition: tabctrl.cxx:1321
void SetAccessibleName(sal_uInt16 nItemId, const OUString &rStr)
Definition: tabctrl.cxx:1962
std::unique_ptr< ImplTabCtrlData > mpTabCtrlData
Definition: tabctrl.hxx:45
virtual void SetSizePixel(const Size &rNewSize) override
Definition: tabctrl.cxx:1329
virtual void Resize() override
Definition: tabctrl.cxx:1344
sal_uInt16 GetPagePos(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1789
void SetPageVisible(sal_uInt16 nPageId, bool bVisible=true)
Definition: tabctrl.cxx:1754
OUString GetPageName(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:2002
SAL_DLLPRIVATE tools::Rectangle ImplGetTabRect(sal_uInt16 nPos, tools::Long nWidth=-1, tools::Long nHeight=-1)
Definition: tabctrl.cxx:549
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
SAL_DLLPRIVATE Size ImplCalculateRequisition(sal_uInt16 &nHeaderHeight) const
Definition: tabctrl.cxx:2036
void SetPageName(sal_uInt16 nPageId, const OUString &rName) const
Definition: tabctrl.cxx:1994
tools::Long mnLastWidth
Definition: tabctrl.hxx:46
TabPage * GetTabPage(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1907
virtual void ImplActivateTabPage(bool bNext)
Definition: tabctrl.cxx:732
void SetPageEnabled(sal_uInt16 nPageId, bool bEnable=true)
Definition: tabctrl.cxx:1731
void SetCurPageId(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1819
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: tabctrl.cxx:1042
void SetTabPageSizePixel(const Size &rSize)
Definition: tabctrl.cxx:1628
bool mbSmallInvalidate
Definition: tabctrl.hxx:53
virtual void SetPosPixel(const Point &rPos) override
Definition: tabctrl.cxx:1337
sal_uInt16 mnActPageId
Definition: tabctrl.hxx:48
virtual void LoseFocus() override
Definition: tabctrl.cxx:1379
SAL_DLLPRIVATE bool ImplPosCurTabPage()
Definition: tabctrl.cxx:712
virtual Size GetOptimalSize() const override
Definition: tabctrl.cxx:2110
void SelectTabPage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1861
bool mbLayoutDirty
Definition: tabctrl.hxx:54
virtual void KeyInput(const KeyEvent &rKEvt) override
Definition: tabctrl.cxx:1052
void SetPageImage(sal_uInt16 nPageId, const Image &rImage)
Definition: tabctrl.cxx:2012
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: tabctrl.cxx:100
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: tabctrl.cxx:1527
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: tabctrl.cxx:1081
SAL_DLLPRIVATE bool ImplHandleKeyEvent(const KeyEvent &rKeyEvent)
Definition: tabctrl.cxx:991
void InsertPage(sal_uInt16 nPageId, const OUString &rText, sal_uInt16 nPos=TAB_APPEND)
Definition: tabctrl.cxx:1638
sal_uInt16 GetCurPageId() const
Definition: tabctrl.cxx:1853
SAL_DLLPRIVATE ImplTabItem * ImplGetItem(sal_uInt16 nId) const
Definition: tabctrl.cxx:213
OUString const & GetPageText(sal_uInt16 nPageId) const
Definition: tabctrl.cxx:1937
virtual bool ImplPlaceTabs(tools::Long nWidth)
Definition: tabctrl.cxx:391
sal_uInt16 GetPageId(sal_uInt16 nPos) const
Definition: tabctrl.cxx:1782
SAL_DLLPRIVATE void ImplShowFocus()
Definition: tabctrl.cxx:749
void SetHelpText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1946
bool mbFormat
Definition: tabctrl.hxx:50
virtual void Command(const CommandEvent &rCEvt) override
Definition: tabctrl.cxx:1456
Link< TabControl *, void > maActivateHdl
Definition: tabctrl.hxx:55
void SetPageText(sal_uInt16 nPageId, const OUString &rText)
Definition: tabctrl.cxx:1917
tools::Long mnLastHeight
Definition: tabctrl.hxx:47
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: tabctrl.cxx:1559
void ImplInitSettings()
Definition: ctrl.cxx:423
virtual FactoryFunction GetUITestFactory() const override
Definition: tabctrl.cxx:2144
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:2149
bool DeactivatePage()
Definition: tabctrl.cxx:1623
SAL_DLLPRIVATE void ImplDrawItem(vcl::RenderContext &rRenderContext, ImplTabItem const *pItem, const tools::Rectangle &rCurRect, bool bFirstInGroup, bool bLastInGroup)
Definition: tabctrl.cxx:799
void RemovePage(sal_uInt16 nPageId)
Definition: tabctrl.cxx:1687
virtual void queue_resize(StateChangedType eReason=StateChangedType::Layout) override
Definition: tabctrl.cxx:2115
virtual void SetPosSizePixel(const Point &rNewPos, const Size &rNewSize) override
Definition: tabpage.cxx:197
static int m_nOverlap
TabitemFlags mnAlignment
A toolbar: contains all those icons, typically below the menu bar.
Definition: toolbox.hxx:74
static Size getLayoutRequisition(const vcl::Window &rWindow)
Definition: layout.cxx:170
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
static VclPtr< reference_type > Create(Arg &&... arg)
A construction helper for VclPtr.
Definition: vclptr.hxx:127
bool mbUseNativeFocus
Definition: window.h:361
void put(std::u16string_view pPropName, const OUString &rPropValue)
ScopedJsonWriterStruct startStruct()
ScopedJsonWriterArray startArray(std::string_view)
constexpr Point Center() const
bool Contains(const Point &rPOINT) const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr void SetRight(tools::Long v)
constexpr Size GetSize() const
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr void SetBottom(tools::Long v)
constexpr Point BottomRight() const
constexpr Point TopRight() const
constexpr tools::Long GetHeight() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
constexpr Point BottomLeft() const
void SetTransparent(bool bTransparent)
Definition: font/font.cxx:125
bool IsMod1() const
Definition: keycod.hxx:56
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
bool IsShift() const
Definition: keycod.hxx:54
void Intersect(const tools::Rectangle &rRegion)
Definition: region.cxx:583
bool IsEmpty() const
Definition: region.cxx:229
void Union(const tools::Rectangle &rRegion)
Definition: region.cxx:507
Point OutputToScreenPixel(const Point &rPos) const
Definition: window.cxx:2806
const Wallpaper & GetBackground() const
Definition: window3.cxx:63
void SetFont(const vcl::Font &rNewFont)
Definition: window3.cxx:59
void SetInputContext(const InputContext &rInputContext)
Definition: window.cxx:2076
bool IsReallyVisible() const
Definition: window2.cxx:1133
virtual void GetFocus()
Definition: window.cxx:1841
vcl::Window * GetParent() const
Definition: window2.cxx:1123
virtual void RequestHelp(const HelpEvent &rHEvt)
Definition: window.cxx:1869
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
bool HasChildPathFocus(bool bSystemWindow=false) const
Definition: window.cxx:3004
Point LogicToPixel(const Point &rLogicPt) const
Definition: window3.cxx:131
bool IsMouseOver() const
Definition: mouse.cxx:596
const OUString & get_id() const
Get the ID of the window.
Definition: window.cxx:3935
virtual void Command(const CommandEvent &rCEvt)
Definition: window.cxx:1923
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
void HideFocus()
Definition: window2.cxx:95
void GrabFocus()
Definition: window.cxx:2976
bool IsUpdateMode() const
Definition: window2.cxx:1199
bool IsChildTransparentModeEnabled() const
Definition: window2.cxx:1053
bool HasFocus() const
Definition: window.cxx:2981
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)
Definition: window3.cxx:79
Point GetLastPointerPosPixel()
Definition: mouse.cxx:552
tools::Long GetTextHeight() const
Height where any character of the current font fits; in logic coordinates.
Definition: window3.cxx:65
WinBits GetStyle() const
Definition: window2.cxx:979
const AllSettings & GetSettings() const
Definition: window3.cxx:129
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Definition: window.cxx:2187
virtual void KeyInput(const KeyEvent &rKEvt)
Definition: window.cxx:1805
bool IsReallyShown() const
Definition: window2.cxx:1138
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect)
Definition: paint.cxx:1020
const OUString & GetHelpId() const
Definition: window2.cxx:859
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:52
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
Definition: window3.cxx:74
bool IsDialog() const
Definition: window2.cxx:1028
Window(WindowType nType)
Definition: window.cxx:95
::OutputDevice const * GetOutDev() const
Definition: window.cxx:567
const vcl::Font & GetFont() const
Definition: window3.cxx:58
void Hide()
Definition: window.hxx:879
SAL_DLLPRIVATE WindowImpl * ImplGetWindowImpl() const
Definition: window.hxx:528
void AddChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:323
virtual void ShowFocus(const tools::Rectangle &rRect)
Definition: window2.cxx:53
virtual void DumpAsPropertyTree(tools::JsonWriter &)
Dumps itself and potentially its children to a property tree, to be written easily to JSON.
Definition: window.cxx:3356
virtual Size GetSizePixel() const
Definition: window.cxx:2402
Size GetOutputSizePixel() const
Definition: window3.cxx:89
bool IsControlBackground() const
Definition: window2.cxx:1113
virtual void DataChanged(const DataChangedEvent &rDCEvt)
Definition: event.cxx:36
Point GetPointerPosPixel()
Definition: mouse.cxx:540
virtual void LoseFocus()
Definition: window.cxx:1855
const Color & GetControlBackground() const
Definition: window2.cxx:1108
OUString GetAccessibleName() const
void SetPaintTransparent(bool bTransparent)
Definition: paint.cxx:1025
bool IsVisible() const
Definition: window2.cxx:1128
void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
Definition: paint.cxx:1143
bool IsDefaultSize() const
Definition: window2.cxx:1179
virtual bool set_property(const OUString &rKey, const OUString &rValue)
Definition: window2.cxx:1478
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2812
void RemoveChildEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:328
OUString GetAccessibleDescription() const
bool IsEnabled() const
Definition: window2.cxx:1148
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle, SystemParentData *pSystemParentData)
Definition: window.cxx:941
const OUString & GetHelpText() const
Definition: window.cxx:3090
void EnableChildTransparentMode(bool bEnable=true)
Definition: window2.cxx:1048
void SetHelpId(const OUString &)
Definition: window2.cxx:854
SAL_DLLPRIVATE void ImplControlFocus(GetFocusFlags nFlags=GetFocusFlags::NONE)
Definition: dlgctrl.cxx:516
void SetBackground()
Definition: window3.cxx:100
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
virtual void SetCurPageId(const OUString &rName) override
float u
sal_Int32 nState
std::function< std::unique_ptr< UIObject >(vcl::Window *)> FactoryFunction
const sal_uInt16 idx[]
sal_Int32 nIndex
sal_Int64 n
constexpr sal_uInt16 KEY_LEFT
Definition: keycodes.hxx:112
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
constexpr sal_uInt16 KEY_TAB
Definition: keycodes.hxx:121
constexpr sal_uInt16 KEY_RIGHT
Definition: keycodes.hxx:113
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
sal_uInt16 nPos
const long LONG_MAX
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
@ DrawDisabled
this flags lets the item be drawn disabled (e.g.
@ DisableSelection
this flag disables a selection of an entry completely.
aStr
static std::deque< size_t > GetEndOfLineIndexes(const std::vector< sal_Int32 > &rWidthsOf, sal_Int32 nLineWidth)
Definition: tabctrl.cxx:295
int i
long Long
sal_Int16 nId
QPRO_FUNC_TYPE nType
ImplSVNWFData maNWFData
Definition: svdata.hxx:403
bool mbNoFocusRects
Definition: svdata.hxx:325
VclPtr< ListBox > mpListBox
Definition: tabctrl.cxx:94
std::vector< ImplTabItem > maItemList
Definition: tabctrl.cxx:93
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:77
#define TAB_ITEM_OFFSET_X
Space to the left and right of the tabitem.
Definition: tabctrl.cxx:49
IMPL_LINK_NOARG(TabControl, ImplListBoxSelectHdl, ListBox &, void)
Definition: tabctrl.cxx:1024
static bool lcl_canPaint(const vcl::RenderContext &rRenderContext, const tools::Rectangle &rDrawRect, const tools::Rectangle &rItemRect)
Definition: tabctrl.cxx:1071
#define TAB_PAGERECT
Definition: tabctrl.cxx:98
#define TAB_EXTRASPACE_X
Definition: tabctrl.cxx:52
#define TAB_BORDER_LEFT
Definition: tabctrl.cxx:53
#define TAB_BORDER_RIGHT
Definition: tabctrl.cxx:55
IMPL_LINK(TabControl, ImplWindowEventListener, VclWindowEvent &, rEvent, void)
Definition: tabctrl.cxx:1029
static bool lcl_isValidPage(const ImplTabItem &rItem, bool &bFound)
Definition: tabctrl.cxx:2275
static void lcl_AdjustSingleLineTabs(tools::Long nMaxWidth, ImplTabCtrlData *pTabCtrlData)
Definition: tabctrl.cxx:368
#define TAB_OFFSET
Definition: tabctrl.cxx:47
#define TAB_BORDER_TOP
Definition: tabctrl.cxx:54
#define TAB_ITEM_OFFSET_Y
Space to the top and bottom of the tabitem.
Definition: tabctrl.cxx:51
#define TAB_BORDER_BOTTOM
Definition: tabctrl.cxx:56
#define TAB_APPEND
Definition: tabctrl.hxx:38
#define TAB_PAGE_NOTFOUND
Definition: tabctrl.hxx:39
OUString removeMnemonicFromString(OUString const &rStr)
bool bVisible
#define SAL_MAX_INT32
@ TabpagePageTextChanged
StateChangedType
Definition: window.hxx:291
@ NoChildren
The child windows are not invalidated.
sal_Int64 WinBits
Definition: wintypes.hxx:109
WinBits const WB_VCENTER
Definition: wintypes.hxx:150
WinBits const WB_DIALOGCONTROL
Definition: wintypes.hxx:113
WinBits const WB_CENTER
Definition: wintypes.hxx:147
WinBits const WB_DROPDOWN
Definition: wintypes.hxx:159
WinBits const WB_STDTABCONTROL
Definition: wintypes.hxx:219
WindowType
Definition: wintypes.hxx:27
WinBits const WB_NOTABSTOP
Definition: wintypes.hxx:141
WinBits const WB_GROUP
Definition: wintypes.hxx:142
WinBits const WB_NOGROUP
Definition: wintypes.hxx:143
WinBits const WB_NODIALOGCONTROL
Definition: wintypes.hxx:114
WinBits const WB_TABSTOP
Definition: wintypes.hxx:140
WinBits const WB_NOBORDER
Definition: wintypes.hxx:116