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