bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / window / splitwin.cxx
blobf2bba6b2ceaf095969c14c8f2358619b065eea0b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
22 #include <o3tl/safeint.hxx>
23 #include <sal/log.hxx>
25 #include <vcl/event.hxx>
26 #include <vcl/wall.hxx>
27 #include <vcl/help.hxx>
28 #include <vcl/splitwin.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/ptrstyle.hxx>
32 #include <svdata.hxx>
33 #include <strings.hrc>
36 #define SPLITWIN_SPLITSIZEEX 4
37 #define SPLITWIN_SPLITSIZEAUTOHIDE 72
38 #define SPLITWIN_SPLITSIZEFADE 72
40 #define SPLIT_HORZ (sal_uInt16(0x0001))
41 #define SPLIT_VERT (sal_uInt16(0x0002))
42 #define SPLIT_WINDOW (sal_uInt16(0x0004))
43 #define SPLIT_NOSPLIT (sal_uInt16(0x8000))
45 namespace {
47 class ImplSplitItem
49 public:
50 ImplSplitItem();
52 tools::Long mnSize;
53 tools::Long mnPixSize;
54 tools::Long mnLeft;
55 tools::Long mnTop;
56 tools::Long mnWidth;
57 tools::Long mnHeight;
58 tools::Long mnSplitPos;
59 tools::Long mnSplitSize;
60 tools::Long mnOldSplitPos;
61 tools::Long mnOldSplitSize;
62 tools::Long mnOldWidth;
63 tools::Long mnOldHeight;
64 std::unique_ptr<ImplSplitSet> mpSet;
65 VclPtr<vcl::Window> mpWindow;
66 VclPtr<vcl::Window> mpOrgParent;
67 sal_uInt16 mnId;
68 SplitWindowItemFlags mnBits;
69 bool mbFixed;
70 bool mbSubSize;
71 /// Minimal width or height of the item. -1 means no restriction.
72 tools::Long mnMinSize;
73 /// Maximal width or height of the item. -1 means no restriction.
74 tools::Long mnMaxSize;
79 class ImplSplitSet
81 public:
82 ImplSplitSet();
84 std::vector< ImplSplitItem > mvItems;
85 tools::Long mnLastSize;
86 tools::Long mnSplitSize;
87 sal_uInt16 mnId;
88 bool mbCalcPix;
91 ImplSplitItem::ImplSplitItem()
92 : mnSize(0)
93 , mnPixSize(0)
94 , mnLeft(0)
95 , mnTop(0)
96 , mnWidth(0)
97 , mnHeight(0)
98 , mnSplitPos(0)
99 , mnSplitSize(0)
100 , mnOldSplitPos(0)
101 , mnOldSplitSize(0)
102 , mnOldWidth(0)
103 , mnOldHeight(0)
104 , mnId(0)
105 , mnBits(SplitWindowItemFlags::NONE)
106 , mbFixed(false)
107 , mbSubSize(false)
108 , mnMinSize(-1)
109 , mnMaxSize(-1)
113 ImplSplitSet::ImplSplitSet() :
114 mnLastSize( 0 ),
115 mnSplitSize( SPLITWIN_SPLITSIZE ),
116 mnId( 0 ),
117 mbCalcPix( true )
121 /** Check whether the given size is inside the valid range defined by
122 [rItem.mnMinSize,rItem.mnMaxSize]. When it is not inside it then return
123 the upper or lower bound, respectively. Otherwise return the given size
124 unmodified.
125 Note that either mnMinSize and/or mnMaxSize can be -1 in which case the
126 size has not lower or upper bound.
128 namespace {
129 tools::Long ValidateSize (const tools::Long nSize, const ImplSplitItem & rItem)
131 if (rItem.mnMinSize>=0 && nSize<rItem.mnMinSize)
132 return rItem.mnMinSize;
133 else if (rItem.mnMaxSize>0 && nSize>rItem.mnMaxSize)
134 return rItem.mnMaxSize;
135 else
136 return nSize;
140 static void ImplCalcBorder( WindowAlign eAlign,
141 tools::Long& rLeft, tools::Long& rTop,
142 tools::Long& rRight, tools::Long& rBottom )
144 switch ( eAlign )
146 case WindowAlign::Top:
147 rLeft = 2;
148 rTop = 2;
149 rRight = 2;
150 rBottom = 0;
151 break;
152 case WindowAlign::Left:
153 rLeft = 0;
154 rTop = 2;
155 rRight = 2;
156 rBottom = 2;
157 break;
158 case WindowAlign::Bottom:
159 rLeft = 2;
160 rTop = 0;
161 rRight = 2;
162 rBottom = 2;
163 break;
164 default:
165 rLeft = 0;
166 rTop = 2;
167 rRight = 2;
168 rBottom = 2;
169 break;
173 void SplitWindow::ImplDrawBorder(vcl::RenderContext& rRenderContext)
175 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
176 tools::Long nDX = mnDX;
177 tools::Long nDY = mnDY;
179 switch (meAlign)
181 case WindowAlign::Bottom:
182 break;
183 case WindowAlign::Top:
184 break;
185 case WindowAlign::Left:
186 break;
187 default:
188 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
189 rRenderContext.DrawLine(Point(0, 0), Point( 0, nDY));
190 rRenderContext.DrawLine(Point(0, nDY), Point(nDX, nDY));
194 void SplitWindow::ImplDrawBorderLine(vcl::RenderContext& rRenderContext)
196 if (!mbFadeOut)
197 return;
199 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
200 tools::Long nDX = mnDX;
201 tools::Long nDY = mnDY;
203 switch (meAlign)
205 case WindowAlign::Left:
206 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
207 rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );
209 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
210 rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
211 break;
212 case WindowAlign::Right:
213 break;
214 case WindowAlign::Top:
215 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
216 rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) );
218 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
219 rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN ) );
220 break;
221 case WindowAlign::Bottom:
222 rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
223 rRenderContext.DrawLine( Point( 0, 5 ), Point( nDX-1, 5 ) );
225 rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
226 rRenderContext.DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, SPLITWIN_SPLITSIZEEXLN ) );
227 break;
231 static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, sal_uInt16 nId )
233 if ( pSet->mnId == nId )
234 return pSet;
236 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
238 for ( const auto& rItem : rItems )
240 if ( rItem.mnId == nId )
241 return rItem.mpSet.get();
244 for ( auto& rItem : rItems )
246 if ( rItem.mpSet )
248 ImplSplitSet* pFindSet = ImplFindSet( rItem.mpSet.get(), nId );
249 if ( pFindSet )
250 return pFindSet;
254 return nullptr;
257 static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, sal_uInt16 nId, sal_uInt16& rPos )
259 size_t nItems = pSet->mvItems.size();
260 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
262 for ( size_t i = 0; i < nItems; i++ )
264 if ( rItems[i].mnId == nId )
266 rPos = i;
267 return pSet;
271 for ( auto& rItem : rItems )
273 if ( rItem.mpSet )
275 ImplSplitSet* pFindSet = ImplFindItem( rItem.mpSet.get(), nId, rPos );
276 if ( pFindSet )
277 return pFindSet;
281 return nullptr;
284 static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, vcl::Window* pWindow )
286 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
288 for ( auto& rItem : rItems )
290 if ( rItem.mpWindow == pWindow )
291 return rItem.mnId;
292 else
294 if ( rItem.mpSet )
296 sal_uInt16 nId = ImplFindItem( rItem.mpSet.get(), pWindow );
297 if ( nId )
298 return nId;
303 return 0;
306 static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, const Point& rPos,
307 bool bRows, bool bDown = true )
309 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
311 for ( auto& rItem : rItems )
313 if ( rItem.mnWidth && rItem.mnHeight )
315 Point aPoint( rItem.mnLeft, rItem.mnTop );
316 Size aSize( rItem.mnWidth, rItem.mnHeight );
317 tools::Rectangle aRect( aPoint, aSize );
318 if ( bRows )
320 if ( bDown )
321 aRect.AdjustBottom(pSet->mnSplitSize );
322 else
323 aRect.AdjustTop( -(pSet->mnSplitSize) );
325 else
327 if ( bDown )
328 aRect.AdjustRight(pSet->mnSplitSize );
329 else
330 aRect.AdjustLeft( -(pSet->mnSplitSize) );
333 if ( aRect.Contains( rPos ) )
335 if ( rItem.mpSet && !rItem.mpSet->mvItems.empty() )
337 return ImplFindItem( rItem.mpSet.get(), rPos,
338 !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
340 else
341 return rItem.mnId;
346 return 0;
349 static void ImplCalcSet( ImplSplitSet* pSet,
350 tools::Long nSetLeft, tools::Long nSetTop,
351 tools::Long nSetWidth, tools::Long nSetHeight,
352 bool bRows, bool bDown = true )
354 if ( pSet->mvItems.empty() )
355 return;
357 sal_uInt16 nMins;
358 sal_uInt16 nCalcItems;
359 size_t nItems = pSet->mvItems.size();
360 sal_uInt16 nAbsItems;
361 tools::Long nCalcSize;
362 tools::Long nPos;
363 tools::Long nMaxPos;
364 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
365 bool bEmpty;
367 // calculate sizes
368 if ( bRows )
369 nCalcSize = nSetHeight;
370 else
371 nCalcSize = nSetWidth;
372 nCalcSize -= (rItems.size()-1)*pSet->mnSplitSize;
373 if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) )
375 tools::Long nPercentFactor = 10;
376 tools::Long nRelCount = 0;
377 tools::Long nPercent = 0;
378 tools::Long nRelPercent = 0;
379 tools::Long nAbsSize = 0;
380 tools::Long nCurSize = 0;
381 for ( const auto& rItem : rItems )
383 if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
384 nRelCount += rItem.mnSize;
385 else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
386 nPercent += rItem.mnSize;
387 else
388 nAbsSize += rItem.mnSize;
390 // map relative values to percentages (percentage here one tenth of a percent)
391 nPercent *= nPercentFactor;
392 if ( nRelCount )
394 tools::Long nRelPercentBase = 1000;
395 while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) )
397 nRelPercentBase *= 10;
398 nPercentFactor *= 10;
400 if ( nPercent < nRelPercentBase )
402 nRelPercent = (nRelPercentBase-nPercent)/nRelCount;
403 nPercent += nRelPercent*nRelCount;
405 else
406 nRelPercent = 0;
408 if ( !nPercent )
409 nPercent = 1;
410 tools::Long nSizeDelta = nCalcSize-nAbsSize;
411 for ( auto& rItem : rItems )
413 if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
415 if ( nSizeDelta <= 0 )
416 rItem.mnPixSize = 0;
417 else
418 rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nRelPercent)/nPercent;
420 else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
422 if ( nSizeDelta <= 0 )
423 rItem.mnPixSize = 0;
424 else
425 rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nPercentFactor)/nPercent;
427 else
428 rItem.mnPixSize = rItem.mnSize;
429 nCurSize += rItem.mnPixSize;
432 pSet->mbCalcPix = false;
433 pSet->mnLastSize = nCalcSize;
435 // adapt window
436 nSizeDelta = nCalcSize-nCurSize;
437 if ( nSizeDelta )
439 nAbsItems = 0;
440 tools::Long nSizeWinSize = 0;
442 // first resize absolute items relative
443 for ( const auto& rItem : rItems )
445 if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
447 nAbsItems++;
448 nSizeWinSize += rItem.mnPixSize;
451 // do not compensate rounding errors here
452 if ( (nAbsItems < o3tl::make_unsigned(std::abs( nSizeDelta ))) && nSizeWinSize )
454 tools::Long nNewSizeWinSize = 0;
456 for ( auto& rItem : rItems )
458 if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
460 rItem.mnPixSize += (nSizeDelta*rItem.mnPixSize)/nSizeWinSize;
461 nNewSizeWinSize += rItem.mnPixSize;
465 nSizeDelta -= nNewSizeWinSize-nSizeWinSize;
468 // compensate rounding errors now
469 sal_uInt16 j = 0;
470 nMins = 0;
471 while ( nSizeDelta && (nItems != nMins) )
473 // determine which items we can calculate
474 nCalcItems = 0;
475 while ( !nCalcItems )
477 for ( auto& rItem : rItems )
479 rItem.mbSubSize = false;
481 if ( j >= 2 )
482 rItem.mbSubSize = true;
483 else
485 if ( (nSizeDelta > 0) || rItem.mnPixSize )
487 if ( j >= 1 )
488 rItem.mbSubSize = true;
489 else
491 if ( (j == 0) && (rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
492 rItem.mbSubSize = true;
497 if ( rItem.mbSubSize )
498 nCalcItems++;
501 j++;
504 // subtract size of individual items
505 tools::Long nErrorSum = nSizeDelta % nCalcItems;
506 tools::Long nCurSizeDelta = nSizeDelta / nCalcItems;
507 nMins = 0;
508 for ( auto& rItem : rItems )
510 if ( rItem.mbSubSize )
512 tools::Long* pSize = &(rItem.mnPixSize);
513 tools::Long nTempErr;
515 if ( nErrorSum )
517 if ( nErrorSum < 0 )
518 nTempErr = -1;
519 else
520 nTempErr = 1;
522 else
523 nTempErr = 0;
525 if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
527 tools::Long nTemp = *pSize;
528 if ( nTemp )
530 *pSize -= nTemp;
531 nSizeDelta += nTemp;
533 nMins++;
535 else
537 *pSize += nCurSizeDelta;
538 nSizeDelta -= nCurSizeDelta;
539 if ( nTempErr && (*pSize || (nTempErr > 0)) )
541 *pSize += nTempErr;
542 nSizeDelta -= nTempErr;
543 nErrorSum -= nTempErr;
552 // calculate maximum size
553 if ( bRows )
555 nPos = nSetTop;
556 if ( !bDown )
557 nMaxPos = nSetTop-nSetHeight;
558 else
559 nMaxPos = nSetTop+nSetHeight;
561 else
563 nPos = nSetLeft;
564 if ( !bDown )
565 nMaxPos = nSetLeft-nSetWidth;
566 else
567 nMaxPos = nSetLeft+nSetWidth;
570 // order windows and adapt values
571 for ( size_t i = 0; i < nItems; i++ )
573 rItems[i].mnOldSplitPos = rItems[i].mnSplitPos;
574 rItems[i].mnOldSplitSize = rItems[i].mnSplitSize;
575 rItems[i].mnOldWidth = rItems[i].mnWidth;
576 rItems[i].mnOldHeight = rItems[i].mnHeight;
578 bEmpty = false;
579 if ( bDown )
581 if ( nPos+rItems[i].mnPixSize > nMaxPos )
582 bEmpty = true;
584 else
586 nPos -= rItems[i].mnPixSize;
587 if ( nPos < nMaxPos )
588 bEmpty = true;
591 if ( bEmpty )
593 rItems[i].mnWidth = 0;
594 rItems[i].mnHeight = 0;
595 rItems[i].mnSplitSize = 0;
597 else
599 if ( bRows )
601 rItems[i].mnLeft = nSetLeft;
602 rItems[i].mnTop = nPos;
603 rItems[i].mnWidth = nSetWidth;
604 rItems[i].mnHeight = rItems[i].mnPixSize;
606 else
608 rItems[i].mnLeft = nPos;
609 rItems[i].mnTop = nSetTop;
610 rItems[i].mnWidth = rItems[i].mnPixSize;
611 rItems[i].mnHeight = nSetHeight;
614 if ( i > nItems-1 )
615 rItems[i].mnSplitSize = 0;
616 else
618 rItems[i].mnSplitSize = pSet->mnSplitSize;
619 if ( bDown )
621 rItems[i].mnSplitPos = nPos+rItems[i].mnPixSize;
622 if ( rItems[i].mnSplitPos+rItems[i].mnSplitSize > nMaxPos )
623 rItems[i].mnSplitSize = nMaxPos-rItems[i].mnSplitPos;
625 else
627 rItems[i].mnSplitPos = nPos-pSet->mnSplitSize;
628 if ( rItems[i].mnSplitPos < nMaxPos )
629 rItems[i].mnSplitSize = rItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos;
634 if ( !bDown )
635 nPos -= pSet->mnSplitSize;
636 else
637 nPos += rItems[i].mnPixSize+pSet->mnSplitSize;
640 // calculate Sub-Set's
641 for ( auto& rItem : rItems )
643 if ( rItem.mpSet && rItem.mnWidth && rItem.mnHeight )
645 ImplCalcSet( rItem.mpSet.get(),
646 rItem.mnLeft, rItem.mnTop,
647 rItem.mnWidth, rItem.mnHeight,
648 !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
652 // set fixed
653 for ( auto& rItem : rItems )
655 rItem.mbFixed = false;
656 if ( rItem.mnBits & SplitWindowItemFlags::Fixed )
657 rItem.mbFixed = true;
658 else
660 // this item is also fixed if Child-Set is available,
661 // if a child is fixed
662 if ( rItem.mpSet )
664 for ( auto const & j: rItem.mpSet->mvItems )
666 if ( j.mbFixed )
668 rItem.mbFixed = true;
669 break;
677 void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, bool bHide,
678 bool bRows )
680 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
682 if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate )
684 for ( const auto& rItem : rItems )
686 if ( rItem.mnSplitSize )
688 // invalidate all, if applicable or only a small part
689 if ( (rItem.mnOldSplitPos != rItem.mnSplitPos) ||
690 (rItem.mnOldSplitSize != rItem.mnSplitSize) ||
691 (rItem.mnOldWidth != rItem.mnWidth) ||
692 (rItem.mnOldHeight != rItem.mnHeight) )
694 tools::Rectangle aRect;
696 // invalidate old rectangle
697 if ( bRows )
699 aRect.SetLeft( rItem.mnLeft );
700 aRect.SetRight( rItem.mnLeft+rItem.mnOldWidth-1 );
701 aRect.SetTop( rItem.mnOldSplitPos );
702 aRect.SetBottom( aRect.Top() + rItem.mnOldSplitSize );
704 else
706 aRect.SetTop( rItem.mnTop );
707 aRect.SetBottom( rItem.mnTop+rItem.mnOldHeight-1 );
708 aRect.SetLeft( rItem.mnOldSplitPos );
709 aRect.SetRight( aRect.Left() + rItem.mnOldSplitSize );
711 pWindow->Invalidate( aRect );
712 // invalidate new rectangle
713 if ( bRows )
715 aRect.SetLeft( rItem.mnLeft );
716 aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
717 aRect.SetTop( rItem.mnSplitPos );
718 aRect.SetBottom( aRect.Top() + rItem.mnSplitSize );
720 else
722 aRect.SetTop( rItem.mnTop );
723 aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
724 aRect.SetLeft( rItem.mnSplitPos );
725 aRect.SetRight( aRect.Left() + rItem.mnSplitSize );
727 pWindow->Invalidate( aRect );
729 // invalidate complete set, as these areas
730 // are not cluttered by windows
731 if ( rItem.mpSet && rItem.mpSet->mvItems.empty() )
733 aRect.SetLeft( rItem.mnLeft );
734 aRect.SetTop( rItem.mnTop );
735 aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
736 aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
737 pWindow->Invalidate( aRect );
744 // position windows
745 for ( auto& rItem : rItems )
747 if ( rItem.mpSet )
749 bool bTempHide = bHide;
750 if ( !rItem.mnWidth || !rItem.mnHeight )
751 bTempHide = true;
752 ImplCalcSet2( pWindow, rItem.mpSet.get(), bTempHide,
753 !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
755 else
757 if ( rItem.mnWidth && rItem.mnHeight && !bHide )
759 Point aPos( rItem.mnLeft, rItem.mnTop );
760 Size aSize( rItem.mnWidth, rItem.mnHeight );
761 rItem.mpWindow->SetPosSizePixel( aPos, aSize );
763 else
764 rItem.mpWindow->Hide();
768 // show windows and reset flag
769 for ( auto& rItem : rItems )
771 if ( rItem.mpWindow && rItem.mnWidth && rItem.mnHeight && !bHide )
772 rItem.mpWindow->Show();
776 static void ImplCalcLogSize( std::vector< ImplSplitItem > & rItems, size_t nItems )
778 // update original sizes
779 size_t i;
780 tools::Long nRelSize = 0;
781 tools::Long nPerSize = 0;
783 for ( i = 0; i < nItems; i++ )
785 if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
786 nRelSize += rItems[i].mnPixSize;
787 else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
788 nPerSize += rItems[i].mnPixSize;
790 nPerSize += nRelSize;
791 for ( i = 0; i < nItems; i++ )
793 if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
795 if ( nRelSize )
796 rItems[i].mnSize = (rItems[i].mnPixSize+(nRelSize/2))/nRelSize;
797 else
798 rItems[i].mnSize = 1;
800 else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
802 if ( nPerSize )
803 rItems[i].mnSize = (rItems[i].mnPixSize*100)/nPerSize;
804 else
805 rItems[i].mnSize = 1;
807 else
808 rItems[i].mnSize = rItems[i].mnPixSize;
812 static void ImplDrawSplit(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet, bool bRows, bool bDown)
814 if (pSet->mvItems.empty())
815 return;
817 size_t nItems = pSet->mvItems.size();
818 tools::Long nPos;
819 tools::Long nTop;
820 tools::Long nBottom;
821 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
822 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
824 for (size_t i = 0; i < nItems-1; i++)
826 if (rItems[i].mnSplitSize)
828 nPos = rItems[i].mnSplitPos;
830 tools::Long nItemSplitSize = rItems[i].mnSplitSize;
831 tools::Long nSplitSize = pSet->mnSplitSize;
832 if (bRows)
834 nTop = rItems[i].mnLeft;
835 nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
837 if (bDown || (nItemSplitSize >= nSplitSize))
839 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
840 rRenderContext.DrawLine(Point(nTop, nPos + 1), Point(nBottom, nPos + 1));
842 nPos += nSplitSize-2;
843 if ((!bDown && (nItemSplitSize >= 2)) ||
844 (bDown && (nItemSplitSize >= nSplitSize - 1)))
846 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
847 rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
849 nPos++;
850 if (!bDown || (nItemSplitSize >= nSplitSize))
852 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
853 rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
856 else
858 nTop = rItems[i].mnTop;
859 nBottom = rItems[i].mnTop+pSet->mvItems[i].mnHeight-1;
861 if (bDown || (nItemSplitSize >= nSplitSize))
863 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
864 rRenderContext.DrawLine(Point(nPos + 1, nTop), Point(nPos+1, nBottom));
866 nPos += pSet->mnSplitSize - 2;
867 if ((!bDown && (nItemSplitSize >= 2)) ||
868 (bDown && (nItemSplitSize >= nSplitSize - 1)))
870 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
871 rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
873 nPos++;
874 if (!bDown || (nItemSplitSize >= nSplitSize))
876 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
877 rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
883 for ( auto& rItem : rItems )
885 if (rItem.mpSet && rItem.mnWidth && rItem.mnHeight)
887 ImplDrawSplit(rRenderContext, rItem.mpSet.get(), !(rItem.mnBits & SplitWindowItemFlags::ColSet), true/*bDown*/);
892 sal_uInt16 SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
893 tools::Long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos,
894 bool bRows )
896 if ( pSet->mvItems.empty() )
897 return 0;
899 sal_uInt16 nSplitTest;
900 size_t nItems = pSet->mvItems.size();
901 tools::Long nMPos1;
902 tools::Long nMPos2;
903 tools::Long nPos;
904 tools::Long nTop;
905 tools::Long nBottom;
906 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
908 if ( bRows )
910 nMPos1 = rPos.X();
911 nMPos2 = rPos.Y();
913 else
915 nMPos1 = rPos.Y();
916 nMPos2 = rPos.X();
919 for ( size_t i = 0; i < nItems-1; i++ )
921 if ( rItems[i].mnSplitSize )
923 if ( bRows )
925 nTop = rItems[i].mnLeft;
926 nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
928 else
930 nTop = rItems[i].mnTop;
931 nBottom = rItems[i].mnTop+rItems[i].mnHeight-1;
933 nPos = rItems[i].mnSplitPos;
935 if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) &&
936 (nMPos2 >= nPos) && (nMPos2 <= nPos+rItems[i].mnSplitSize) )
938 if ( !rItems[i].mbFixed && !rItems[i+1].mbFixed )
940 rMouseOff = nMPos2-nPos;
941 *ppFoundSet = pSet;
942 rFoundPos = i;
943 if ( bRows )
944 return SPLIT_VERT;
945 else
946 return SPLIT_HORZ;
948 else
949 return SPLIT_NOSPLIT;
954 for ( auto& rItem : rItems )
956 if ( rItem.mpSet )
958 nSplitTest = ImplTestSplit( rItem.mpSet.get(), rPos,
959 rMouseOff, ppFoundSet, rFoundPos,
960 !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
961 if ( nSplitTest )
962 return nSplitTest;
966 return 0;
969 sal_uInt16 SplitWindow::ImplTestSplit( const SplitWindow* pWindow, const Point& rPos,
970 tools::Long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos )
972 // Resizable SplitWindow should be treated different
973 if ( pWindow->mnWinStyle & WB_SIZEABLE )
975 tools::Long nTPos;
976 tools::Long nPos;
977 tools::Long nBorder;
979 if ( pWindow->mbHorz )
981 if ( pWindow->mbBottomRight )
983 nBorder = pWindow->mnBottomBorder;
984 nPos = 0;
986 else
988 nBorder = pWindow->mnTopBorder;
989 nPos = pWindow->mnDY-nBorder;
991 nTPos = rPos.Y();
993 else
995 if ( pWindow->mbBottomRight )
997 nBorder = pWindow->mnRightBorder;
998 nPos = 0;
1000 else
1002 nBorder = pWindow->mnLeftBorder;
1003 nPos = pWindow->mnDX-nBorder;
1005 nTPos = rPos.X();
1007 tools::Long nSplitSize = pWindow->mpMainSet->mnSplitSize-2;
1008 if (pWindow->mbFadeOut)
1009 nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1010 if ( !pWindow->mbBottomRight )
1011 nPos -= nSplitSize;
1012 if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) )
1014 rMouseOff = nTPos-nPos;
1015 *ppFoundSet = pWindow->mpMainSet.get();
1016 if ( !pWindow->mpMainSet->mvItems.empty() )
1017 rFoundPos = pWindow->mpMainSet->mvItems.size() - 1;
1018 else
1019 rFoundPos = 0;
1020 if ( pWindow->mbHorz )
1021 return SPLIT_VERT | SPLIT_WINDOW;
1022 else
1023 return SPLIT_HORZ | SPLIT_WINDOW;
1027 return ImplTestSplit( pWindow->mpMainSet.get(), rPos, rMouseOff, ppFoundSet, rFoundPos,
1028 pWindow->mbHorz );
1031 void SplitWindow::ImplDrawSplitTracking(const Point& rPos)
1033 tools::Rectangle aRect;
1035 if (mnSplitTest & SPLIT_HORZ)
1037 aRect.SetTop( maDragRect.Top() );
1038 aRect.SetBottom( maDragRect.Bottom() );
1039 aRect.SetLeft( rPos.X() );
1040 aRect.SetRight( aRect.Left() + mpSplitSet->mnSplitSize - 1 );
1041 if (!(mnWinStyle & WB_NOSPLITDRAW))
1042 aRect.AdjustRight( -1 );
1043 if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
1045 aRect.AdjustLeft(SPLITWIN_SPLITSIZEEXLN );
1046 aRect.AdjustRight(SPLITWIN_SPLITSIZEEXLN );
1049 else
1051 aRect.SetLeft( maDragRect.Left() );
1052 aRect.SetRight( maDragRect.Right() );
1053 aRect.SetTop( rPos.Y() );
1054 aRect.SetBottom( aRect.Top() + mpSplitSet->mnSplitSize - 1 );
1055 if (!(mnWinStyle & WB_NOSPLITDRAW))
1056 aRect.AdjustBottom( -1 );
1057 if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
1059 aRect.AdjustTop(SPLITWIN_SPLITSIZEEXLN );
1060 aRect.AdjustBottom(SPLITWIN_SPLITSIZEEXLN );
1063 ShowTracking(aRect, ShowTrackFlags::Split);
1066 void SplitWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
1068 mpMainSet.reset(new ImplSplitSet());
1069 mpBaseSet = mpMainSet.get();
1070 mpSplitSet = nullptr;
1071 mpLastSizes = nullptr;
1072 mnDX = 0;
1073 mnDY = 0;
1074 mnLeftBorder = 0;
1075 mnTopBorder = 0;
1076 mnRightBorder = 0;
1077 mnBottomBorder = 0;
1078 mnMaxSize = 0;
1079 mnMouseOff = 0;
1080 meAlign = WindowAlign::Top;
1081 mnWinStyle = nStyle;
1082 mnSplitTest = 0;
1083 mnSplitPos = 0;
1084 mnMouseModifier = 0;
1085 mnMStartPos = 0;
1086 mnMSplitPos = 0;
1087 mbDragFull = false;
1088 mbHorz = true;
1089 mbBottomRight = false;
1090 mbCalc = false;
1091 mbRecalc = true;
1092 mbInvalidate = true;
1093 mbFadeIn = false;
1094 mbFadeOut = false;
1095 mbFadeInDown = false;
1096 mbFadeOutDown = false;
1097 mbFadeInPressed = false;
1098 mbFadeOutPressed = false;
1099 mbFadeNoButtonMode = false;
1101 if ( nStyle & WB_NOSPLITDRAW )
1103 mpMainSet->mnSplitSize -= 2;
1104 mbInvalidate = false;
1107 if ( nStyle & WB_BORDER )
1109 ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
1110 mnRightBorder, mnBottomBorder );
1112 else
1114 mnLeftBorder = 0;
1115 mnTopBorder = 0;
1116 mnRightBorder = 0;
1117 mnBottomBorder = 0;
1120 DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) );
1122 ImplInitSettings();
1125 void SplitWindow::ImplInitSettings()
1127 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1129 Color aColor;
1130 if ( IsControlBackground() )
1131 aColor = GetControlBackground();
1132 else if ( Window::GetStyle() & WB_3DLOOK )
1133 aColor = rStyleSettings.GetFaceColor();
1134 else
1135 aColor = rStyleSettings.GetWindowColor();
1136 SetBackground( aColor );
1139 SplitWindow::SplitWindow( vcl::Window* pParent, WinBits nStyle ) :
1140 DockingWindow( WindowType::SPLITWINDOW, "vcl::SplitWindow maLayoutIdle" )
1142 ImplInit( pParent, nStyle );
1145 SplitWindow::~SplitWindow()
1147 disposeOnce();
1150 void SplitWindow::dispose()
1152 // delete Sets
1153 mpMainSet.reset();
1154 DockingWindow::dispose();
1157 void SplitWindow::ImplSetWindowSize( tools::Long nDelta )
1159 if ( !nDelta )
1160 return;
1162 Size aSize = GetSizePixel();
1163 switch ( meAlign )
1165 case WindowAlign::Top:
1166 aSize.AdjustHeight(nDelta );
1167 SetSizePixel( aSize );
1168 break;
1169 case WindowAlign::Bottom:
1171 maDragRect.AdjustTop(nDelta );
1172 Point aPos = GetPosPixel();
1173 aPos.AdjustY( -nDelta );
1174 aSize.AdjustHeight(nDelta );
1175 SetPosSizePixel( aPos, aSize );
1176 break;
1178 case WindowAlign::Left:
1179 aSize.AdjustWidth(nDelta );
1180 SetSizePixel( aSize );
1181 break;
1182 case WindowAlign::Right:
1183 default:
1185 maDragRect.AdjustLeft(nDelta );
1186 Point aPos = GetPosPixel();
1187 aPos.AdjustX( -nDelta );
1188 aSize.AdjustWidth(nDelta );
1189 SetPosSizePixel( aPos, aSize );
1190 break;
1194 SplitResize();
1197 Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize )
1199 Size aSize( aNewSize );
1200 tools::Long nSplitSize = mpMainSet->mnSplitSize-2;
1202 if (mbFadeOut)
1203 nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1205 // if the window is sizeable and if it does not contain a relative window,
1206 // the size is determined according to MainSet
1207 if ( mnWinStyle & WB_SIZEABLE )
1209 tools::Long nCalcSize = 0;
1210 std::vector< ImplSplitItem* >::size_type i;
1212 for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
1214 if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
1215 break;
1216 else
1217 nCalcSize += mpMainSet->mvItems[i].mnSize;
1220 if ( i == mpMainSet->mvItems.size() )
1222 tools::Long nDelta = 0;
1223 tools::Long nCurSize;
1225 if ( mbHorz )
1226 nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
1227 else
1228 nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
1229 nCurSize -= nSplitSize;
1230 nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
1232 nDelta = nCalcSize-nCurSize;
1233 if ( !nDelta )
1234 return aSize;
1236 switch ( meAlign )
1238 case WindowAlign::Top:
1239 aSize.AdjustHeight(nDelta );
1240 break;
1241 case WindowAlign::Bottom:
1242 aSize.AdjustHeight(nDelta );
1243 break;
1244 case WindowAlign::Left:
1245 aSize.AdjustWidth(nDelta );
1246 break;
1247 case WindowAlign::Right:
1248 default:
1249 aSize.AdjustWidth(nDelta );
1250 break;
1255 return aSize;
1258 void SplitWindow::ImplCalcLayout()
1260 if ( !mbCalc || !mbRecalc || mpMainSet->mvItems.empty() )
1261 return;
1263 tools::Long nSplitSize = mpMainSet->mnSplitSize-2;
1264 if (mbFadeOut)
1265 nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1267 // if the window is sizeable and if it does not contain a relative window,
1268 // the size is determined according to MainSet
1269 if ( mnWinStyle & WB_SIZEABLE )
1271 tools::Long nCalcSize = 0;
1272 std::vector<ImplSplitItem *>::size_type i;
1274 for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
1276 if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
1277 break;
1278 else
1279 nCalcSize += mpMainSet->mvItems[i].mnSize;
1282 if ( i == mpMainSet->mvItems.size() )
1284 tools::Long nCurSize;
1285 if ( mbHorz )
1286 nCurSize = mnDY-mnTopBorder-mnBottomBorder;
1287 else
1288 nCurSize = mnDX-mnLeftBorder-mnRightBorder;
1289 nCurSize -= nSplitSize;
1290 nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
1292 mbRecalc = false;
1293 ImplSetWindowSize( nCalcSize-nCurSize );
1294 mbRecalc = true;
1298 if ( (mnDX <= 0) || (mnDY <= 0) )
1299 return;
1301 // pre-calculate sizes/position
1302 tools::Long nL;
1303 tools::Long nT;
1304 tools::Long nW;
1305 tools::Long nH;
1307 if ( mbHorz )
1309 if ( mbBottomRight )
1310 nT = mnDY-mnBottomBorder;
1311 else
1312 nT = mnTopBorder;
1313 nL = mnLeftBorder;
1315 else
1317 if ( mbBottomRight )
1318 nL = mnDX-mnRightBorder;
1319 else
1320 nL = mnLeftBorder;
1321 nT = mnTopBorder;
1323 nW = mnDX-mnLeftBorder-mnRightBorder;
1324 nH = mnDY-mnTopBorder-mnBottomBorder;
1325 if ( mnWinStyle & WB_SIZEABLE )
1327 if ( mbHorz )
1328 nH -= nSplitSize;
1329 else
1330 nW -= nSplitSize;
1333 // calculate sets recursive
1334 ImplCalcSet( mpMainSet.get(), nL, nT, nW, nH, mbHorz, !mbBottomRight );
1335 ImplCalcSet2( this, mpMainSet.get(), false, mbHorz );
1336 mbCalc = false;
1339 void SplitWindow::ImplUpdate()
1341 mbCalc = true;
1343 if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
1345 if ( !mpMainSet->mvItems.empty() )
1346 ImplCalcLayout();
1347 else
1348 Invalidate();
1352 void SplitWindow::ImplSplitMousePos( Point& rMousePos )
1354 if ( mnSplitTest & SPLIT_HORZ )
1356 rMousePos.AdjustX( -mnMouseOff );
1357 if ( rMousePos.X() < maDragRect.Left() )
1358 rMousePos.setX( maDragRect.Left() );
1359 else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() )
1360 rMousePos.setX( maDragRect.Right()-mpSplitSet->mnSplitSize+1 );
1361 // store in screen coordinates due to FullDrag
1362 mnMSplitPos = OutputToScreenPixel( rMousePos ).X();
1364 else
1366 rMousePos.AdjustY( -mnMouseOff );
1367 if ( rMousePos.Y() < maDragRect.Top() )
1368 rMousePos.setY( maDragRect.Top() );
1369 else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() )
1370 rMousePos.setY( maDragRect.Bottom()-mpSplitSet->mnSplitSize+1 );
1371 mnMSplitPos = OutputToScreenPixel( rMousePos ).Y();
1375 void SplitWindow::ImplGetButtonRect( tools::Rectangle& rRect, bool bTest ) const
1377 tools::Long nSplitSize = mpMainSet->mnSplitSize-1;
1378 if (mbFadeOut || mbFadeIn)
1379 nSplitSize += SPLITWIN_SPLITSIZEEX;
1381 tools::Long nButtonSize = 0;
1382 if ( mbFadeIn )
1383 nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
1384 if ( mbFadeOut )
1385 nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
1386 tools::Long nCenterEx = 0;
1387 if ( mbHorz )
1388 nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
1389 else
1390 nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
1391 tools::Long nEx = 0;
1392 if ( nCenterEx > 0 )
1393 nEx += nCenterEx;
1395 switch ( meAlign )
1397 case WindowAlign::Top:
1398 rRect.SetLeft( mnLeftBorder+nEx );
1399 rRect.SetTop( mnDY-mnBottomBorder-nSplitSize );
1400 rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
1401 rRect.SetBottom( mnDY-mnBottomBorder-1 );
1402 if ( bTest )
1404 rRect.AdjustTop( -mnTopBorder );
1405 rRect.AdjustBottom(mnBottomBorder );
1407 break;
1408 case WindowAlign::Bottom:
1409 rRect.SetLeft( mnLeftBorder+nEx );
1410 rRect.SetTop( mnTopBorder );
1411 rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
1412 rRect.SetBottom( mnTopBorder+nSplitSize-1 );
1413 if ( bTest )
1415 rRect.AdjustTop( -mnTopBorder );
1416 rRect.AdjustBottom(mnBottomBorder );
1418 break;
1419 case WindowAlign::Left:
1420 rRect.SetLeft( mnDX-mnRightBorder-nSplitSize );
1421 rRect.SetTop( mnTopBorder+nEx );
1422 rRect.SetRight( mnDX-mnRightBorder-1 );
1423 rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
1424 if ( bTest )
1426 rRect.AdjustLeft( -mnLeftBorder );
1427 rRect.AdjustRight(mnRightBorder );
1429 break;
1430 case WindowAlign::Right:
1431 rRect.SetLeft( mnLeftBorder );
1432 rRect.SetTop( mnTopBorder+nEx );
1433 rRect.SetRight( mnLeftBorder+nSplitSize-1 );
1434 rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
1435 if ( bTest )
1437 rRect.AdjustLeft( -mnLeftBorder );
1438 rRect.AdjustRight(mnRightBorder );
1440 break;
1444 void SplitWindow::ImplGetFadeInRect( tools::Rectangle& rRect, bool bTest ) const
1446 tools::Rectangle aRect;
1448 if ( mbFadeIn )
1449 ImplGetButtonRect( aRect, bTest );
1451 rRect = aRect;
1454 void SplitWindow::ImplGetFadeOutRect( tools::Rectangle& rRect ) const
1456 tools::Rectangle aRect;
1458 if ( mbFadeOut )
1459 ImplGetButtonRect( aRect, false );
1461 rRect = aRect;
1464 void SplitWindow::ImplDrawGrip(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bHorizontal, bool bLeft)
1466 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1468 Color aColor;
1470 if (rRect.Contains(GetPointerPosPixel()))
1472 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, rRect, 2, false, false, false);
1474 aColor = rStyleSettings.GetDarkShadowColor();
1476 else
1478 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
1479 rRenderContext.SetFillColor(rStyleSettings.GetDarkShadowColor());
1481 rRenderContext.DrawRect(rRect);
1483 aColor = rStyleSettings.GetFaceColor();
1486 AntialiasingFlags nAA = rRenderContext.GetAntialiasing();
1487 rRenderContext.SetAntialiasing(nAA | AntialiasingFlags::PixelSnapHairline | AntialiasingFlags::Enable);
1489 tools::Long nWidth = rRect.getOpenWidth();
1490 tools::Long nWidthHalf = nWidth / 2;
1491 tools::Long nHeight = rRect.getOpenHeight();
1492 tools::Long nHeightHalf = nHeight / 2;
1494 tools::Long nLeft = rRect.Left();
1495 tools::Long nRight = rRect.Right();
1496 tools::Long nTop = rRect.Top();
1497 tools::Long nBottom = rRect.Bottom();
1498 tools::Long nMargin = 1;
1500 rRenderContext.SetLineColor(aColor);
1501 rRenderContext.SetFillColor(aColor);
1503 tools::Polygon aPoly(3);
1505 if (bHorizontal)
1507 tools::Long nCenter = nLeft + nWidthHalf;
1509 if (bLeft)
1511 aPoly.SetPoint(Point(nCenter, nTop + nMargin), 0);
1512 aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 1);
1513 aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 2);
1515 else
1517 aPoly.SetPoint(Point(nCenter, nBottom - nMargin), 0);
1518 aPoly.SetPoint(Point(nCenter - nHeightHalf, nTop + nMargin), 1);
1519 aPoly.SetPoint(Point(nCenter + nHeightHalf, nTop + nMargin), 2);
1521 rRenderContext.DrawPolygon(aPoly);
1523 else
1525 tools::Long nCenter = nTop + nHeightHalf;
1527 if (bLeft)
1529 aPoly.SetPoint(Point(nLeft + nMargin, nCenter), 0);
1530 aPoly.SetPoint(Point(nRight - nMargin, nCenter - nWidthHalf), 1);
1531 aPoly.SetPoint(Point(nRight - nMargin, nCenter + nWidthHalf), 2);
1533 else
1535 aPoly.SetPoint(Point(nRight - nMargin, nCenter), 0);
1536 aPoly.SetPoint(Point(nLeft + nMargin, nCenter - nWidthHalf), 1);
1537 aPoly.SetPoint(Point(nLeft + nMargin, nCenter + nWidthHalf), 2);
1539 rRenderContext.DrawPolygon(aPoly);
1542 rRenderContext.SetAntialiasing(nAA);
1545 void SplitWindow::ImplDrawFadeIn(vcl::RenderContext& rRenderContext)
1547 if (!mbFadeIn)
1548 return;
1550 tools::Rectangle aTempRect;
1551 ImplGetFadeInRect(aTempRect);
1553 bool bLeft = true;
1554 switch (meAlign)
1556 case WindowAlign::Top:
1557 case WindowAlign::Left:
1558 bLeft = false;
1559 break;
1560 case WindowAlign::Bottom:
1561 case WindowAlign::Right:
1562 default:
1563 bLeft = true;
1564 break;
1567 ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
1570 void SplitWindow::ImplDrawFadeOut(vcl::RenderContext& rRenderContext)
1572 if (!mbFadeOut)
1573 return;
1575 tools::Rectangle aTempRect;
1576 ImplGetFadeOutRect(aTempRect);
1578 bool bLeft = true;
1579 switch (meAlign)
1581 case WindowAlign::Bottom:
1582 case WindowAlign::Right:
1583 bLeft = false;
1584 break;
1585 case WindowAlign::Top:
1586 case WindowAlign::Left:
1587 default:
1588 bLeft = true;
1589 break;
1592 ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
1595 void SplitWindow::ImplStartSplit( const MouseEvent& rMEvt )
1597 Point aMousePosPixel = rMEvt.GetPosPixel();
1598 mnSplitTest = ImplTestSplit( this, aMousePosPixel, mnMouseOff, &mpSplitSet, mnSplitPos );
1600 if ( !mnSplitTest || (mnSplitTest & SPLIT_NOSPLIT) )
1601 return;
1603 ImplSplitItem* pSplitItem;
1604 tools::Long nCurMaxSize;
1605 bool bPropSmaller;
1607 mnMouseModifier = rMEvt.GetModifier();
1608 bPropSmaller = (mnMouseModifier & KEY_SHIFT) && (o3tl::make_unsigned(mnSplitPos+1) < mpSplitSet->mvItems.size());
1610 // here we can set the maximum size
1611 StartSplit();
1613 if ( mnMaxSize )
1614 nCurMaxSize = mnMaxSize;
1615 else
1617 Size aSize = GetParent()->GetOutputSizePixel();
1618 if ( mbHorz )
1619 nCurMaxSize = aSize.Height();
1620 else
1621 nCurMaxSize = aSize.Width();
1624 if ( !mpSplitSet->mvItems.empty() )
1626 bool bDown = true;
1627 if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
1628 bDown = false;
1630 pSplitItem = &mpSplitSet->mvItems[mnSplitPos];
1631 maDragRect.SetLeft( pSplitItem->mnLeft );
1632 maDragRect.SetTop( pSplitItem->mnTop );
1633 maDragRect.SetRight( pSplitItem->mnLeft+pSplitItem->mnWidth-1 );
1634 maDragRect.SetBottom( pSplitItem->mnTop+pSplitItem->mnHeight-1 );
1636 if ( mnSplitTest & SPLIT_HORZ )
1638 if ( bDown )
1639 maDragRect.AdjustRight(mpSplitSet->mnSplitSize );
1640 else
1641 maDragRect.AdjustLeft( -(mpSplitSet->mnSplitSize) );
1643 else
1645 if ( bDown )
1646 maDragRect.AdjustBottom(mpSplitSet->mnSplitSize );
1647 else
1648 maDragRect.AdjustTop( -(mpSplitSet->mnSplitSize) );
1651 if ( mnSplitPos )
1653 tools::Long nTemp = mnSplitPos;
1654 while ( nTemp )
1656 pSplitItem = &mpSplitSet->mvItems[nTemp-1];
1657 if ( pSplitItem->mbFixed )
1658 break;
1659 else
1661 if ( mnSplitTest & SPLIT_HORZ )
1663 if ( bDown )
1664 maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
1665 else
1666 maDragRect.AdjustRight(pSplitItem->mnPixSize );
1668 else
1670 if ( bDown )
1671 maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
1672 else
1673 maDragRect.AdjustBottom(pSplitItem->mnPixSize );
1676 nTemp--;
1680 if ( (mpSplitSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) && !bPropSmaller )
1682 if ( bDown )
1684 if ( mbHorz )
1685 maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
1686 else
1687 maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
1689 else
1691 if ( mbHorz )
1692 maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
1693 else
1694 maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
1697 else
1699 std::vector<ImplSplitItem *>::size_type nTemp = mnSplitPos+1;
1700 while ( nTemp < mpSplitSet->mvItems.size() )
1702 pSplitItem = &mpSplitSet->mvItems[nTemp];
1703 if ( pSplitItem->mbFixed )
1704 break;
1705 else
1707 if ( mnSplitTest & SPLIT_HORZ )
1709 if ( bDown )
1710 maDragRect.AdjustRight(pSplitItem->mnPixSize );
1711 else
1712 maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
1714 else
1716 if ( bDown )
1717 maDragRect.AdjustBottom(pSplitItem->mnPixSize );
1718 else
1719 maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
1722 nTemp++;
1726 else
1728 maDragRect.SetLeft( mnLeftBorder );
1729 maDragRect.SetTop( mnTopBorder );
1730 maDragRect.SetRight( mnDX-mnRightBorder-1 );
1731 maDragRect.SetBottom( mnDY-mnBottomBorder-1 );
1732 if ( mbHorz )
1734 if ( mbBottomRight )
1735 maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
1736 else
1737 maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
1739 else
1741 if ( mbBottomRight )
1742 maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
1743 else
1744 maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
1748 StartTracking();
1750 mbDragFull = bool(GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Split);
1752 ImplSplitMousePos( aMousePosPixel );
1754 if (!mbDragFull)
1756 ImplDrawSplitTracking(aMousePosPixel);
1758 else
1760 std::vector< ImplSplitItem >& rItems = mpSplitSet->mvItems;
1761 sal_uInt16 nItems = mpSplitSet->mvItems.size();
1762 mpLastSizes.reset(new tools::Long[nItems*2]);
1763 for ( sal_uInt16 i = 0; i < nItems; i++ )
1765 mpLastSizes[i*2] = rItems[i].mnSize;
1766 mpLastSizes[i*2+1] = rItems[i].mnPixSize;
1769 mnMStartPos = mnMSplitPos;
1771 PointerStyle eStyle = PointerStyle::Arrow;
1772 if ( mnSplitTest & SPLIT_HORZ )
1773 eStyle = PointerStyle::HSplit;
1774 else if ( mnSplitTest & SPLIT_VERT )
1775 eStyle = PointerStyle::VSplit;
1777 SetPointer( eStyle );
1780 void SplitWindow::StartSplit()
1784 void SplitWindow::Split()
1786 maSplitHdl.Call( this );
1789 void SplitWindow::SplitResize()
1793 void SplitWindow::FadeIn()
1797 void SplitWindow::FadeOut()
1801 void SplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
1803 if ( !rMEvt.IsLeft() || rMEvt.IsMod2() )
1805 DockingWindow::MouseButtonDown( rMEvt );
1806 return;
1809 Point aMousePosPixel = rMEvt.GetPosPixel();
1810 tools::Rectangle aTestRect;
1812 mbFadeNoButtonMode = false;
1814 ImplGetFadeOutRect( aTestRect );
1815 if ( aTestRect.Contains( aMousePosPixel ) )
1817 mbFadeOutDown = true;
1818 mbFadeOutPressed = true;
1819 Invalidate();
1821 else
1823 ImplGetFadeInRect( aTestRect, true );
1824 if ( aTestRect.Contains( aMousePosPixel ) )
1826 mbFadeInDown = true;
1827 mbFadeInPressed = true;
1828 Invalidate();
1830 else if ( !aTestRect.IsEmpty() && !(mnWinStyle & WB_SIZEABLE) )
1832 mbFadeNoButtonMode = true;
1833 FadeIn();
1834 return;
1838 if ( mbFadeInDown || mbFadeOutDown )
1839 StartTracking();
1840 else
1841 ImplStartSplit( rMEvt );
1844 void SplitWindow::MouseMove( const MouseEvent& rMEvt )
1846 if ( IsTracking() )
1847 return;
1849 Point aPos = rMEvt.GetPosPixel();
1850 tools::Long nTemp;
1851 ImplSplitSet* pTempSplitSet;
1852 sal_uInt16 nTempSplitPos;
1853 sal_uInt16 nSplitTest = ImplTestSplit( this, aPos, nTemp, &pTempSplitSet, nTempSplitPos );
1854 PointerStyle eStyle = PointerStyle::Arrow;
1855 tools::Rectangle aFadeInRect;
1856 tools::Rectangle aFadeOutRect;
1858 ImplGetFadeInRect( aFadeInRect );
1859 ImplGetFadeOutRect( aFadeOutRect );
1860 if ( !aFadeInRect.Contains( aPos ) &&
1861 !aFadeOutRect.Contains( aPos ) )
1863 if ( nSplitTest && !(nSplitTest & SPLIT_NOSPLIT) )
1865 if ( nSplitTest & SPLIT_HORZ )
1866 eStyle = PointerStyle::HSplit;
1867 else if ( nSplitTest & SPLIT_VERT )
1868 eStyle = PointerStyle::VSplit;
1872 SetPointer( eStyle );
1875 void SplitWindow::Tracking( const TrackingEvent& rTEvt )
1877 Point aMousePosPixel = rTEvt.GetMouseEvent().GetPosPixel();
1879 if ( mbFadeInDown )
1881 if ( rTEvt.IsTrackingEnded() )
1883 mbFadeInDown = false;
1884 if ( mbFadeInPressed )
1886 mbFadeInPressed = false;
1887 Invalidate();
1889 if ( !rTEvt.IsTrackingCanceled() )
1890 FadeIn();
1893 else
1895 tools::Rectangle aTestRect;
1896 ImplGetFadeInRect( aTestRect, true );
1897 bool bNewPressed = aTestRect.Contains( aMousePosPixel );
1898 if ( bNewPressed != mbFadeInPressed )
1900 mbFadeInPressed = bNewPressed;
1901 Invalidate();
1905 else if ( mbFadeOutDown )
1907 if ( rTEvt.IsTrackingEnded() )
1909 mbFadeOutDown = false;
1910 if ( mbFadeOutPressed )
1912 mbFadeOutPressed = false;
1913 Invalidate();
1915 if ( !rTEvt.IsTrackingCanceled() )
1916 FadeOut();
1919 else
1921 tools::Rectangle aTestRect;
1922 ImplGetFadeOutRect( aTestRect );
1923 bool bNewPressed = aTestRect.Contains( aMousePosPixel );
1924 if ( !bNewPressed )
1926 mbFadeOutPressed = bNewPressed;
1927 Invalidate();
1929 // We need a mouseevent with a position inside the button for the
1930 // ImplStartSplit function!
1931 MouseEvent aOrgMEvt = rTEvt.GetMouseEvent();
1932 MouseEvent aNewMEvt( aTestRect.Center(), aOrgMEvt.GetClicks(),
1933 aOrgMEvt.GetMode(), aOrgMEvt.GetButtons(),
1934 aOrgMEvt.GetModifier() );
1936 ImplStartSplit( aNewMEvt );
1937 mbFadeOutDown = false;
1941 else
1943 ImplSplitMousePos( aMousePosPixel );
1944 bool bSplit = true;
1945 if ( mbDragFull )
1947 if ( rTEvt.IsTrackingEnded() )
1949 if ( rTEvt.IsTrackingCanceled() )
1951 std::vector< ImplSplitItem >& rItems = mpSplitSet->mvItems;
1952 size_t nItems = rItems.size();
1953 for ( size_t i = 0; i < nItems; i++ )
1955 rItems[i].mnSize = mpLastSizes[i*2];
1956 rItems[i].mnPixSize = mpLastSizes[i*2+1];
1958 ImplUpdate();
1959 Split();
1961 bSplit = false;
1964 else
1966 if ( rTEvt.IsTrackingEnded() )
1968 HideTracking();
1969 bSplit = !rTEvt.IsTrackingCanceled();
1971 else
1973 ImplDrawSplitTracking(aMousePosPixel);
1974 bSplit = false;
1978 if ( bSplit )
1980 bool bPropSmaller = (mnMouseModifier & KEY_SHIFT) != 0;
1981 bool bPropGreater = (mnMouseModifier & KEY_MOD1) != 0;
1982 tools::Long nDelta = mnMSplitPos-mnMStartPos;
1984 if ( (mnSplitTest & SPLIT_WINDOW) && mpMainSet->mvItems.empty() )
1986 if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
1987 nDelta *= -1;
1988 ImplSetWindowSize( nDelta );
1990 else
1992 tools::Long nNewSize = mpSplitSet->mvItems[mnSplitPos].mnPixSize;
1993 if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
1994 nNewSize -= nDelta;
1995 else
1996 nNewSize += nDelta;
1997 SplitItem( mpSplitSet->mvItems[mnSplitPos].mnId, nNewSize,
1998 bPropSmaller, bPropGreater );
2001 Split();
2003 if ( mbDragFull )
2005 PaintImmediately();
2006 mnMStartPos = mnMSplitPos;
2010 if ( rTEvt.IsTrackingEnded() )
2012 mpLastSizes.reset();
2013 mpSplitSet = nullptr;
2014 mnMouseOff = 0;
2015 mnMStartPos = 0;
2016 mnMSplitPos = 0;
2017 mnMouseModifier = 0;
2018 mnSplitTest = 0;
2019 mnSplitPos = 0;
2024 bool SplitWindow::PreNotify( NotifyEvent& rNEvt )
2026 if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
2028 const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
2029 if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
2031 // trigger redraw if mouse over state has changed
2032 tools::Rectangle aFadeInRect;
2033 tools::Rectangle aFadeOutRect;
2034 ImplGetFadeInRect( aFadeInRect );
2035 ImplGetFadeOutRect( aFadeOutRect );
2037 if ( aFadeInRect.Contains( GetPointerPosPixel() ) != aFadeInRect.Contains( GetLastPointerPosPixel() ) )
2038 Invalidate( aFadeInRect );
2039 if ( aFadeOutRect.Contains( GetPointerPosPixel() ) != aFadeOutRect.Contains( GetLastPointerPosPixel() ) )
2040 Invalidate( aFadeOutRect );
2042 if( pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
2044 Invalidate( aFadeInRect );
2045 Invalidate( aFadeOutRect );
2049 return Window::PreNotify( rNEvt );
2052 void SplitWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2054 if (mnWinStyle & WB_BORDER)
2055 ImplDrawBorder(rRenderContext);
2057 ImplDrawBorderLine(rRenderContext);
2058 ImplDrawFadeOut(rRenderContext);
2059 ImplDrawFadeIn(rRenderContext);
2061 // draw splitter
2062 if (!(mnWinStyle & WB_NOSPLITDRAW))
2064 ImplDrawSplit(rRenderContext, mpMainSet.get(), mbHorz, !mbBottomRight);
2068 void SplitWindow::Resize()
2070 Size aSize = GetOutputSizePixel();
2071 mnDX = aSize.Width();
2072 mnDY = aSize.Height();
2074 ImplUpdate();
2075 Invalidate();
2078 void SplitWindow::RequestHelp( const HelpEvent& rHEvt )
2080 // no keyboard help for splitwin
2081 if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) && !rHEvt.KeyboardActivated() )
2083 Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
2084 tools::Rectangle aHelpRect;
2085 TranslateId pHelpResId;
2087 ImplGetFadeInRect( aHelpRect, true );
2088 if ( aHelpRect.Contains( aMousePosPixel ) )
2089 pHelpResId = SV_HELPTEXT_FADEIN;
2090 else
2092 ImplGetFadeOutRect( aHelpRect );
2093 if ( aHelpRect.Contains( aMousePosPixel ) )
2094 pHelpResId = SV_HELPTEXT_FADEOUT;
2097 // get rectangle
2098 if (pHelpResId)
2100 Point aPt = OutputToScreenPixel( aHelpRect.TopLeft() );
2101 aHelpRect.SetLeft( aPt.X() );
2102 aHelpRect.SetTop( aPt.Y() );
2103 aPt = OutputToScreenPixel( aHelpRect.BottomRight() );
2104 aHelpRect.SetRight( aPt.X() );
2105 aHelpRect.SetBottom( aPt.Y() );
2107 // get and draw text
2108 OUString aStr = VclResId(pHelpResId);
2109 if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
2110 Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aStr );
2111 else
2112 Help::ShowQuickHelp( this, aHelpRect, aStr );
2113 return;
2117 DockingWindow::RequestHelp( rHEvt );
2120 void SplitWindow::StateChanged( StateChangedType nType )
2122 switch ( nType )
2124 case StateChangedType::InitShow:
2125 if ( IsUpdateMode() )
2126 ImplCalcLayout();
2127 break;
2128 case StateChangedType::UpdateMode:
2129 if ( IsUpdateMode() && IsReallyShown() )
2130 ImplCalcLayout();
2131 break;
2132 case StateChangedType::ControlBackground:
2133 ImplInitSettings();
2134 Invalidate();
2135 break;
2136 default:;
2139 DockingWindow::StateChanged( nType );
2142 void SplitWindow::DataChanged( const DataChangedEvent& rDCEvt )
2144 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2145 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
2147 ImplInitSettings();
2148 Invalidate();
2150 else
2151 DockingWindow::DataChanged( rDCEvt );
2154 void SplitWindow::InsertItem( sal_uInt16 nId, vcl::Window* pWindow, tools::Long nSize,
2155 sal_uInt16 nPos, sal_uInt16 nIntoSetId,
2156 SplitWindowItemFlags nBits )
2158 #ifdef DBG_UTIL
2159 sal_uInt16 nDbgDummy;
2160 SAL_WARN_IF( ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl", "SplitWindow::InsertItem() - Id already exists" );
2161 #endif
2163 // Size has to be at least 1.
2164 if ( nSize < 1 )
2165 nSize = 1;
2167 ImplSplitSet* pSet = ImplFindSet( mpMainSet.get(), nIntoSetId );
2168 #ifdef DBG_UTIL
2169 SAL_WARN_IF( !pSet, "vcl", "SplitWindow::InsertItem() - Set not exists" );
2170 #endif
2171 if(!pSet)
2173 return;
2176 // Don't insert further than the end
2177 if ( nPos > pSet->mvItems.size() )
2178 nPos = pSet->mvItems.size();
2180 // Insert in set
2181 pSet->mvItems.emplace( pSet->mvItems.begin() + nPos );
2183 // init new item
2184 ImplSplitItem & aItem = pSet->mvItems[nPos];
2185 aItem.mnSize = nSize;
2186 aItem.mnPixSize = 0;
2187 aItem.mnId = nId;
2188 aItem.mnBits = nBits;
2189 aItem.mnMinSize=-1;
2190 aItem.mnMaxSize=-1;
2192 if ( pWindow )
2194 // New VclPtr reference
2195 aItem.mpWindow = pWindow;
2196 aItem.mpOrgParent = pWindow->GetParent();
2198 // Attach window to SplitWindow.
2199 pWindow->Hide();
2200 pWindow->SetParent( this );
2202 else
2204 ImplSplitSet * pNewSet = new ImplSplitSet();
2205 pNewSet->mnId = nId;
2206 pNewSet->mnSplitSize = pSet->mnSplitSize;
2208 aItem.mpSet.reset(pNewSet);
2211 pSet->mbCalcPix = true;
2213 ImplUpdate();
2216 void SplitWindow::InsertItem( sal_uInt16 nId, tools::Long nSize,
2217 sal_uInt16 nPos, sal_uInt16 nIntoSetId,
2218 SplitWindowItemFlags nBits )
2220 InsertItem( nId, nullptr, nSize, nPos, nIntoSetId, nBits );
2223 void SplitWindow::RemoveItem( sal_uInt16 nId )
2225 #ifdef DBG_UTIL
2226 sal_uInt16 nDbgDummy;
2227 SAL_WARN_IF( !ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl", "SplitWindow::RemoveItem() - Id not found" );
2228 #endif
2230 // search set
2231 sal_uInt16 nPos;
2232 ImplSplitSet* pSet = ImplFindItem( mpMainSet.get(), nId, nPos );
2234 if (!pSet)
2235 return;
2237 ImplSplitItem* pItem = &pSet->mvItems[nPos];
2238 VclPtr<vcl::Window> pWindow = pItem->mpWindow;
2239 VclPtr<vcl::Window> pOrgParent = pItem->mpOrgParent;
2241 // delete set if required
2242 if ( !pWindow )
2243 pItem->mpSet.reset();
2245 // remove item
2246 pSet->mbCalcPix = true;
2247 pSet->mvItems.erase( pSet->mvItems.begin() + nPos );
2249 ImplUpdate();
2251 // to have the least amounts of paints delete window only here
2252 if ( pWindow )
2254 // restore window
2255 pWindow->Hide();
2256 pWindow->SetParent( pOrgParent );
2259 // Clear and delete
2260 pWindow.clear();
2261 pOrgParent.clear();
2264 void SplitWindow::SplitItem( sal_uInt16 nId, tools::Long nNewSize,
2265 bool bPropSmall, bool bPropGreat )
2267 sal_uInt16 nPos;
2268 ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
2270 if (!pSet)
2271 return;
2273 size_t nItems = pSet->mvItems.size();
2274 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
2276 // When there is an explicit minimum or maximum size then move nNewSize
2277 // into that range (when it is not yet already in it.)
2278 nNewSize = ValidateSize(nNewSize, rItems[nPos]);
2280 if ( mbCalc )
2282 rItems[nPos].mnSize = nNewSize;
2283 return;
2286 tools::Long nDelta = nNewSize-rItems[nPos].mnPixSize;
2287 if ( !nDelta )
2288 return;
2290 // calculate area, which could be affected by splitting
2291 sal_uInt16 nMin = 0;
2292 sal_uInt16 nMax = nItems;
2293 for (size_t i = 0; i < nItems; ++i)
2295 if ( rItems[i].mbFixed )
2297 if ( i < nPos )
2298 nMin = i+1;
2299 else
2300 nMax = i;
2304 // treat TopSet different if the window is sizeable
2305 bool bSmall = true;
2306 bool bGreat = true;
2307 if ( (pSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) )
2309 if ( nPos < pSet->mvItems.size()-1 )
2311 if ( !((bPropSmall && bPropGreat) ||
2312 ((nDelta > 0) && bPropSmall) ||
2313 ((nDelta < 0) && bPropGreat)) )
2315 if ( nDelta < 0 )
2316 bGreat = false;
2317 else
2318 bSmall = false;
2321 else
2323 if ( nDelta < 0 )
2324 bGreat = false;
2325 else
2326 bSmall = false;
2329 else if ( nPos >= nMax )
2331 bSmall = false;
2332 bGreat = false;
2334 else if ( nPos && (nPos >= pSet->mvItems.size()-1) )
2336 nPos--;
2337 nDelta *= -1;
2338 std::swap( bPropSmall, bPropGreat );
2341 sal_uInt16 n;
2342 // now splitt the windows
2343 if ( nDelta < 0 )
2345 if ( bGreat )
2347 if ( bPropGreat )
2349 tools::Long nTempDelta = nDelta;
2352 n = nPos+1;
2355 if ( nTempDelta )
2357 rItems[n].mnPixSize++;
2358 nTempDelta++;
2360 n++;
2362 while ( n < nMax );
2364 while ( nTempDelta );
2366 else
2367 rItems[nPos+1].mnPixSize -= nDelta;
2370 if ( bSmall )
2372 if ( bPropSmall )
2376 n = nPos+1;
2379 if ( nDelta && rItems[n-1].mnPixSize )
2381 rItems[n-1].mnPixSize--;
2382 nDelta++;
2385 n--;
2387 while ( n > nMin );
2389 while ( nDelta );
2391 else
2393 n = nPos+1;
2396 if ( rItems[n-1].mnPixSize+nDelta < 0 )
2398 nDelta += rItems[n-1].mnPixSize;
2399 rItems[n-1].mnPixSize = 0;
2401 else
2403 rItems[n-1].mnPixSize += nDelta;
2404 break;
2406 n--;
2408 while ( n > nMin );
2412 else
2414 if ( bGreat )
2416 if ( bPropGreat )
2418 tools::Long nTempDelta = nDelta;
2421 n = nPos+1;
2424 if ( nTempDelta )
2426 rItems[n-1].mnPixSize++;
2427 nTempDelta--;
2429 n--;
2431 while ( n > nMin );
2433 while ( nTempDelta );
2435 else
2436 rItems[nPos].mnPixSize += nDelta;
2439 if ( bSmall )
2441 if ( bPropSmall )
2445 n = nPos+1;
2448 if ( nDelta && rItems[n].mnPixSize )
2450 rItems[n].mnPixSize--;
2451 nDelta--;
2454 n++;
2456 while ( n < nMax );
2458 while ( nDelta );
2460 else
2462 n = nPos+1;
2465 if ( rItems[n].mnPixSize-nDelta < 0 )
2467 nDelta -= rItems[n].mnPixSize;
2468 rItems[n].mnPixSize = 0;
2470 else
2472 rItems[n].mnPixSize -= nDelta;
2473 break;
2475 n++;
2477 while ( n < nMax );
2482 // update original sizes
2483 ImplCalcLogSize( rItems, nItems );
2485 ImplUpdate();
2488 void SplitWindow::SetItemSize( sal_uInt16 nId, tools::Long nNewSize )
2490 sal_uInt16 nPos;
2491 ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
2492 ImplSplitItem* pItem;
2494 if ( !pSet )
2495 return;
2497 // check if size is changed
2498 pItem = &pSet->mvItems[nPos];
2499 if ( pItem->mnSize != nNewSize )
2501 // set new size and re-calculate
2502 pItem->mnSize = nNewSize;
2503 pSet->mbCalcPix = true;
2504 ImplUpdate();
2508 tools::Long SplitWindow::GetItemSize( sal_uInt16 nId ) const
2510 sal_uInt16 nPos;
2511 ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
2513 if ( pSet )
2514 return pSet->mvItems[nPos].mnSize;
2515 else
2516 return 0;
2519 tools::Long SplitWindow::GetItemSize( sal_uInt16 nId, SplitWindowItemFlags nBits ) const
2521 sal_uInt16 nPos;
2522 ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
2524 if ( pSet )
2526 if ( nBits == pSet->mvItems[nPos].mnBits )
2527 return pSet->mvItems[nPos].mnSize;
2528 else
2530 const_cast<SplitWindow*>(this)->ImplCalcLayout();
2532 tools::Long nRelSize = 0;
2533 tools::Long nPerSize = 0;
2534 size_t nItems;
2535 SplitWindowItemFlags nTempBits;
2536 nItems = pSet->mvItems.size();
2537 std::vector< ImplSplitItem >& rItems = pSet->mvItems;
2538 for ( size_t i = 0; i < nItems; i++ )
2540 if ( i == nPos )
2541 nTempBits = nBits;
2542 else
2543 nTempBits = rItems[i].mnBits;
2544 if ( nTempBits & SplitWindowItemFlags::RelativeSize )
2545 nRelSize += rItems[i].mnPixSize;
2546 else if ( nTempBits & SplitWindowItemFlags::PercentSize )
2547 nPerSize += rItems[i].mnPixSize;
2549 nPerSize += nRelSize;
2550 if ( nBits & SplitWindowItemFlags::RelativeSize )
2552 if ( nRelSize )
2553 return (rItems[nPos].mnPixSize+(nRelSize/2))/nRelSize;
2554 else
2555 return 1;
2557 else if ( nBits & SplitWindowItemFlags::PercentSize )
2559 if ( nPerSize )
2560 return (rItems[nPos].mnPixSize*100)/nPerSize;
2561 else
2562 return 1;
2564 else
2565 return rItems[nPos].mnPixSize;
2568 else
2569 return 0;
2572 void SplitWindow::SetItemSizeRange (sal_uInt16 nId, const Range& rRange)
2574 sal_uInt16 nPos;
2575 ImplSplitSet* pSet = ImplFindItem(mpBaseSet, nId, nPos);
2577 if (pSet != nullptr)
2579 pSet->mvItems[nPos].mnMinSize = rRange.Min();
2580 pSet->mvItems[nPos].mnMaxSize = rRange.Max();
2584 sal_uInt16 SplitWindow::GetSet( sal_uInt16 nId ) const
2586 sal_uInt16 nPos;
2587 ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos );
2589 if ( pSet )
2590 return pSet->mnId;
2591 else
2592 return 0;
2595 bool SplitWindow::IsItemValid( sal_uInt16 nId ) const
2597 sal_uInt16 nPos;
2598 ImplSplitSet* pSet = mpBaseSet ? ImplFindItem(mpBaseSet, nId, nPos) : nullptr;
2600 return pSet != nullptr;
2603 sal_uInt16 SplitWindow::GetItemId( vcl::Window* pWindow ) const
2605 return ImplFindItem( mpBaseSet, pWindow );
2608 sal_uInt16 SplitWindow::GetItemId( const Point& rPos ) const
2610 return ImplFindItem( mpBaseSet, rPos, mbHorz, !mbBottomRight );
2613 sal_uInt16 SplitWindow::GetItemPos( sal_uInt16 nId, sal_uInt16 nSetId ) const
2615 ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
2616 sal_uInt16 nPos = SPLITWINDOW_ITEM_NOTFOUND;
2618 if ( pSet )
2620 for ( size_t i = 0; i < pSet->mvItems.size(); i++ )
2622 if ( pSet->mvItems[i].mnId == nId )
2624 nPos = i;
2625 break;
2630 return nPos;
2633 sal_uInt16 SplitWindow::GetItemId( sal_uInt16 nPos ) const
2635 ImplSplitSet* pSet = ImplFindSet( mpBaseSet, 0/*nSetId*/ );
2636 if ( pSet && (nPos < pSet->mvItems.size()) )
2637 return pSet->mvItems[nPos].mnId;
2638 else
2639 return 0;
2642 sal_uInt16 SplitWindow::GetItemCount( sal_uInt16 nSetId ) const
2644 ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
2645 if ( pSet )
2646 return pSet->mvItems.size();
2647 else
2648 return 0;
2651 void SplitWindow::ImplNewAlign()
2653 switch ( meAlign )
2655 case WindowAlign::Top:
2656 mbHorz = true;
2657 mbBottomRight = false;
2658 break;
2659 case WindowAlign::Bottom:
2660 mbHorz = true;
2661 mbBottomRight = true;
2662 break;
2663 case WindowAlign::Left:
2664 mbHorz = false;
2665 mbBottomRight = false;
2666 break;
2667 case WindowAlign::Right:
2668 mbHorz = false;
2669 mbBottomRight = true;
2670 break;
2673 if ( mnWinStyle & WB_BORDER )
2675 ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
2676 mnRightBorder, mnBottomBorder );
2679 if ( IsReallyVisible() && IsUpdateMode() )
2680 Invalidate();
2681 ImplUpdate();
2684 void SplitWindow::SetAlign( WindowAlign eNewAlign )
2686 if ( meAlign != eNewAlign )
2688 meAlign = eNewAlign;
2689 ImplNewAlign();
2693 void SplitWindow::ShowFadeInHideButton()
2695 mbFadeIn = true;
2696 ImplUpdate();
2699 void SplitWindow::ShowFadeOutButton()
2701 mbFadeOut = true;
2702 ImplUpdate();
2705 tools::Long SplitWindow::GetFadeInSize() const
2707 tools::Long n = 0;
2709 if ( mbHorz )
2710 n = mnTopBorder+mnBottomBorder;
2711 else
2712 n = mnLeftBorder+mnRightBorder;
2714 return n+SPLITWIN_SPLITSIZE+SPLITWIN_SPLITSIZEEX-2;
2717 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */