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 <string.h>
21 
22 #include <sal/log.hxx>
23 
24 #include <vcl/event.hxx>
25 #include <vcl/wall.hxx>
26 #include <vcl/help.hxx>
27 #include <vcl/splitwin.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/ptrstyle.hxx>
30 
31 #include <svdata.hxx>
32 #include <strings.hrc>
33 
34 
35 #define SPLITWIN_SPLITSIZE              4
36 #define SPLITWIN_SPLITSIZEEX            4
37 #define SPLITWIN_SPLITSIZEEXLN          7
38 #define SPLITWIN_SPLITSIZEAUTOHIDE      72
39 #define SPLITWIN_SPLITSIZEFADE          72
40 
41 #define SPLIT_HORZ              (sal_uInt16(0x0001))
42 #define SPLIT_VERT              (sal_uInt16(0x0002))
43 #define SPLIT_WINDOW            (sal_uInt16(0x0004))
44 #define SPLIT_NOSPLIT           (sal_uInt16(0x8000))
45 
46 class ImplSplitItem
47 {
48 public:
49     ImplSplitItem();
50 
51     long                mnSize;
52     long                mnPixSize;
53     long                mnLeft;
54     long                mnTop;
55     long                mnWidth;
56     long                mnHeight;
57     long                mnSplitPos;
58     long                mnSplitSize;
59     long                mnOldSplitPos;
60     long                mnOldSplitSize;
61     long                mnOldWidth;
62     long                mnOldHeight;
63     std::unique_ptr<ImplSplitSet> mpSet;
64     VclPtr<vcl::Window> mpWindow;
65     VclPtr<vcl::Window> mpOrgParent;
66     sal_uInt16          mnId;
67     SplitWindowItemFlags mnBits;
68     bool                mbFixed;
69     bool                mbSubSize;
70     /// Minimal width or height of the item.  -1 means no restriction.
71     long                mnMinSize;
72     /// Maximal width or height of the item.  -1 means no restriction.
73     long                mnMaxSize;
74 };
75 
76 
77 class ImplSplitSet
78 {
79 public:
80     ImplSplitSet();
81     ~ImplSplitSet();
82 
83     std::vector< ImplSplitItem > mvItems;
84     std::unique_ptr<Wallpaper>   mpWallpaper;
85     long                mnLastSize;
86     long                mnSplitSize;
87     sal_uInt16          mnId;
88     bool                mbCalcPix;
89 };
90 
ImplSplitItem()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)
110 {
111 }
112 
ImplSplitSet()113 ImplSplitSet::ImplSplitSet() :
114     mnLastSize( 0 ),
115     mnSplitSize( SPLITWIN_SPLITSIZE ),
116     mnId( 0 ),
117     mbCalcPix( true )
118 {
119 }
120 
~ImplSplitSet()121 ImplSplitSet::~ImplSplitSet()
122 {
123     mpWallpaper.reset();
124 }
125 
126 /** Check whether the given size is inside the valid range defined by
127     [rItem.mnMinSize,rItem.mnMaxSize].  When it is not inside it then return
128     the upper or lower bound, respectively. Otherwise return the given size
129     unmodified.
130     Note that either mnMinSize and/or mnMaxSize can be -1 in which case the
131     size has not lower or upper bound.
132 */
133 namespace {
ValidateSize(const long nSize,const ImplSplitItem & rItem)134     long ValidateSize (const long nSize, const ImplSplitItem & rItem)
135     {
136         if (rItem.mnMinSize>=0 && nSize<rItem.mnMinSize)
137             return rItem.mnMinSize;
138         else if (rItem.mnMaxSize>0 && nSize>rItem.mnMaxSize)
139             return rItem.mnMaxSize;
140         else
141             return nSize;
142     }
143 }
144 
ImplCalcBorder(WindowAlign eAlign,long & rLeft,long & rTop,long & rRight,long & rBottom)145 static void ImplCalcBorder( WindowAlign eAlign,
146                             long& rLeft, long& rTop,
147                             long& rRight, long& rBottom )
148 {
149     switch ( eAlign )
150     {
151     case WindowAlign::Top:
152         rLeft   = 2;
153         rTop    = 2;
154         rRight  = 2;
155         rBottom = 0;
156         break;
157     case WindowAlign::Left:
158         rLeft   = 0;
159         rTop    = 2;
160         rRight  = 2;
161         rBottom = 2;
162         break;
163     case WindowAlign::Bottom:
164         rLeft   = 2;
165         rTop    = 0;
166         rRight  = 2;
167         rBottom = 2;
168         break;
169     default:
170         rLeft   = 0;
171         rTop    = 2;
172         rRight  = 2;
173         rBottom = 2;
174         break;
175     }
176 }
177 
ImplDrawBorder(vcl::RenderContext & rRenderContext)178 void SplitWindow::ImplDrawBorder(vcl::RenderContext& rRenderContext)
179 {
180     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
181     long nDX = mnDX;
182     long nDY = mnDY;
183 
184     switch (meAlign)
185     {
186     case WindowAlign::Bottom:
187         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
188         rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
189         rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
190 
191         rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
192         rRenderContext.DrawLine(Point(0, 1), Point(nDX - 1, 1));
193         rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
194         break;
195     case WindowAlign::Top:
196         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
197         rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
198         rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
199 
200         rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
201         rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
202         rRenderContext.DrawLine(Point(0, 1), Point(nDX - 1, 1));
203         break;
204     case WindowAlign::Left:
205         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
206         rRenderContext.DrawLine(Point(nDX - 2, 0), Point(nDX - 2, nDY - 2));
207         rRenderContext.DrawLine(Point(0, 0), Point(nDX - 1, 0));
208         rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 2, nDY - 2));
209 
210         rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
211         rRenderContext.DrawLine(Point(nDX - 1, 0), Point(nDX - 1, nDY - 1));
212         rRenderContext.DrawLine(Point(0, 1), Point(nDX - 3, 1));
213         rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 2, nDY - 1));
214         break;
215     default:
216         rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
217         rRenderContext.DrawLine(Point(0, 0), Point( 0, nDY - 2));
218         rRenderContext.DrawLine(Point(0, 0), Point( nDX - 1, 0));
219         rRenderContext.DrawLine(Point(0, nDY - 2), Point(nDX - 1, nDY - 2));
220 
221         rRenderContext.SetLineColor( rStyleSettings.GetLightColor());
222         rRenderContext.DrawLine(Point(1, 1), Point(1, nDY - 3));
223         rRenderContext.DrawLine(Point(1, 1), Point(nDX - 1, 1));
224         rRenderContext.DrawLine(Point(0, nDY - 1), Point(nDX - 1, nDY - 1));
225     }
226 }
227 
ImplDrawBorderLine(vcl::RenderContext & rRenderContext)228 void SplitWindow::ImplDrawBorderLine(vcl::RenderContext& rRenderContext)
229 {
230     if (mbFadeOut)
231     {
232         const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
233         long nDX = mnDX;
234         long  nDY = mnDY;
235 
236         switch (meAlign)
237         {
238         case WindowAlign::Left:
239             rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
240             rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );
241 
242             rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
243             rRenderContext.DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
244             break;
245         case WindowAlign::Right:
246             rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
247             rRenderContext.DrawLine( Point( SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( SPLITWIN_SPLITSIZEEXLN-1, nDY-2 ) );
248 
249             rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
250             rRenderContext.DrawLine( Point( SPLITWIN_SPLITSIZEEXLN, 1 ), Point( SPLITWIN_SPLITSIZEEXLN, nDY-3 ) );
251             break;
252         case WindowAlign::Top:
253             rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
254             rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) );
255 
256             rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
257             rRenderContext.DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, nDY-SPLITWIN_SPLITSIZEEXLN ) );
258             break;
259         case WindowAlign::Bottom:
260             rRenderContext.SetLineColor( rStyleSettings.GetShadowColor() );
261             rRenderContext.DrawLine( Point( 0, 5 ), Point( nDX-1, 5 ) );
262 
263             rRenderContext.SetLineColor( rStyleSettings.GetLightColor() );
264             rRenderContext.DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-1, SPLITWIN_SPLITSIZEEXLN ) );
265             break;
266         }
267     }
268 }
269 
ImplFindSet(ImplSplitSet * pSet,sal_uInt16 nId)270 static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, sal_uInt16 nId )
271 {
272     if ( pSet->mnId == nId )
273         return pSet;
274 
275     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
276 
277     for ( const auto& rItem : rItems )
278     {
279         if ( rItem.mnId == nId )
280             return rItem.mpSet.get();
281     }
282 
283     for ( auto& rItem : rItems )
284     {
285         if ( rItem.mpSet )
286         {
287             ImplSplitSet* pFindSet = ImplFindSet( rItem.mpSet.get(), nId );
288             if ( pFindSet )
289                 return pFindSet;
290         }
291     }
292 
293     return nullptr;
294 }
295 
ImplFindItem(ImplSplitSet * pSet,sal_uInt16 nId,sal_uInt16 & rPos)296 static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, sal_uInt16 nId, sal_uInt16& rPos )
297 {
298     size_t              nItems = pSet->mvItems.size();
299     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
300 
301     for ( size_t i = 0; i < nItems; i++ )
302     {
303         if ( rItems[i].mnId == nId )
304         {
305             rPos = i;
306             return pSet;
307         }
308     }
309 
310     for ( auto& rItem : rItems )
311     {
312         if ( rItem.mpSet )
313         {
314             ImplSplitSet* pFindSet = ImplFindItem( rItem.mpSet.get(), nId, rPos );
315             if ( pFindSet )
316                 return pFindSet;
317         }
318     }
319 
320     return nullptr;
321 }
322 
ImplFindItem(ImplSplitSet * pSet,vcl::Window * pWindow)323 static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, vcl::Window* pWindow )
324 {
325     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
326 
327     for ( auto& rItem : rItems )
328     {
329         if ( rItem.mpWindow == pWindow )
330             return rItem.mnId;
331         else
332         {
333             if ( rItem.mpSet )
334             {
335                 sal_uInt16 nId = ImplFindItem( rItem.mpSet.get(), pWindow );
336                 if ( nId )
337                     return nId;
338             }
339         }
340     }
341 
342     return 0;
343 }
344 
ImplFindItem(ImplSplitSet * pSet,const Point & rPos,bool bRows,bool bDown=true)345 static sal_uInt16 ImplFindItem( ImplSplitSet* pSet, const Point& rPos,
346                             bool bRows, bool bDown = true )
347 {
348     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
349 
350     for ( auto& rItem : rItems )
351     {
352         if ( rItem.mnWidth && rItem.mnHeight )
353         {
354             Point       aPoint( rItem.mnLeft, rItem.mnTop );
355             Size        aSize( rItem.mnWidth, rItem.mnHeight );
356             tools::Rectangle   aRect( aPoint, aSize );
357             if ( bRows )
358             {
359                 if ( bDown )
360                     aRect.AdjustBottom(pSet->mnSplitSize );
361                 else
362                     aRect.AdjustTop( -(pSet->mnSplitSize) );
363             }
364             else
365             {
366                 if ( bDown )
367                     aRect.AdjustRight(pSet->mnSplitSize );
368                 else
369                     aRect.AdjustLeft( -(pSet->mnSplitSize) );
370             }
371 
372             if ( aRect.IsInside( rPos ) )
373             {
374                 if ( rItem.mpSet && !rItem.mpSet->mvItems.empty() )
375                 {
376                     return ImplFindItem( rItem.mpSet.get(), rPos,
377                                         !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
378                 }
379                 else
380                     return rItem.mnId;
381             }
382         }
383     }
384 
385     return 0;
386 }
387 
ImplCalcSet(ImplSplitSet * pSet,long nSetLeft,long nSetTop,long nSetWidth,long nSetHeight,bool bRows,bool bDown=true)388 static void ImplCalcSet( ImplSplitSet* pSet,
389                          long nSetLeft, long nSetTop,
390                          long nSetWidth, long nSetHeight,
391                          bool bRows, bool bDown = true )
392 {
393     if ( pSet->mvItems.empty() )
394         return;
395 
396     sal_uInt16          nMins;
397     sal_uInt16          nCalcItems;
398     size_t              nItems = pSet->mvItems.size();
399     sal_uInt16          nAbsItems;
400     long                nCalcSize;
401     long                nPos;
402     long                nMaxPos;
403     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
404     bool                bEmpty;
405 
406     // calculate sizes
407     if ( bRows )
408         nCalcSize = nSetHeight;
409     else
410         nCalcSize = nSetWidth;
411     nCalcSize -= (rItems.size()-1)*pSet->mnSplitSize;
412     if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) )
413     {
414         long nPercentFactor = 10;
415         long nRelCount      = 0;
416         long nPercent       = 0;
417         long nRelPercent    = 0;
418         long nAbsSize       = 0;
419         long nCurSize       = 0;
420         for ( const auto& rItem : rItems )
421         {
422             if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
423                 nRelCount += rItem.mnSize;
424             else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
425                 nPercent += rItem.mnSize;
426             else
427                 nAbsSize += rItem.mnSize;
428         }
429         // map relative values to percentages (percentage here one tenth of a percent)
430         nPercent *= nPercentFactor;
431         if ( nRelCount )
432         {
433             long nRelPercentBase = 1000;
434             while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) )
435             {
436                 nRelPercentBase *= 10;
437                 nPercentFactor *= 10;
438             }
439             if ( nPercent < nRelPercentBase )
440             {
441                 nRelPercent = (nRelPercentBase-nPercent)/nRelCount;
442                 nPercent += nRelPercent*nRelCount;
443             }
444             else
445                 nRelPercent = 0;
446         }
447         if ( !nPercent )
448             nPercent = 1;
449         long nSizeDelta = nCalcSize-nAbsSize;
450         for ( auto& rItem : rItems )
451         {
452             if ( rItem.mnBits & SplitWindowItemFlags::RelativeSize )
453             {
454                 if ( nSizeDelta <= 0 )
455                     rItem.mnPixSize = 0;
456                 else
457                     rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nRelPercent)/nPercent;
458             }
459             else if ( rItem.mnBits & SplitWindowItemFlags::PercentSize )
460             {
461                 if ( nSizeDelta <= 0 )
462                     rItem.mnPixSize = 0;
463                 else
464                     rItem.mnPixSize = (nSizeDelta*rItem.mnSize*nPercentFactor)/nPercent;
465             }
466             else
467                 rItem.mnPixSize = rItem.mnSize;
468             nCurSize += rItem.mnPixSize;
469         }
470 
471         pSet->mbCalcPix  = false;
472         pSet->mnLastSize = nCalcSize;
473 
474         // adapt window
475         nSizeDelta  = nCalcSize-nCurSize;
476         if ( nSizeDelta )
477         {
478             nAbsItems       = 0;
479             long nSizeWinSize    = 0;
480 
481             // first resize absolute items relative
482             for ( const auto& rItem : rItems )
483             {
484                 if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
485                 {
486                     nAbsItems++;
487                     nSizeWinSize += rItem.mnPixSize;
488                 }
489             }
490             // do not compensate rounding errors here
491             if ( (nAbsItems < static_cast<sal_uInt16>(std::abs( nSizeDelta ))) && nSizeWinSize )
492             {
493                 long nNewSizeWinSize = 0;
494 
495                 for ( auto& rItem : rItems )
496                 {
497                     if ( !(rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
498                     {
499                         rItem.mnPixSize += (nSizeDelta*rItem.mnPixSize)/nSizeWinSize;
500                         nNewSizeWinSize += rItem.mnPixSize;
501                     }
502                 }
503 
504                 nSizeDelta -= nNewSizeWinSize-nSizeWinSize;
505             }
506 
507             // compensate rounding errors now
508             sal_uInt16 j = 0;
509             nMins       = 0;
510             while ( nSizeDelta && (nItems != nMins) )
511             {
512                 // determine which items we can calculate
513                 nCalcItems = 0;
514                 while ( !nCalcItems )
515                 {
516                     for ( auto& rItem : rItems )
517                     {
518                         rItem.mbSubSize = false;
519 
520                         if ( j >= 2 )
521                             rItem.mbSubSize = true;
522                         else
523                         {
524                             if ( (nSizeDelta > 0) || rItem.mnPixSize )
525                             {
526                                 if ( j >= 1 )
527                                     rItem.mbSubSize = true;
528                                 else
529                                 {
530                                     if ( (j == 0) && (rItem.mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize)) )
531                                         rItem.mbSubSize = true;
532                                 }
533                             }
534                         }
535 
536                         if ( rItem.mbSubSize )
537                             nCalcItems++;
538                     }
539 
540                     j++;
541                 }
542 
543                 // subtract size of individual items
544                 long nErrorSum       = nSizeDelta % nCalcItems;
545                 long nCurSizeDelta   = nSizeDelta / nCalcItems;
546                 nMins           = 0;
547                 for ( auto& rItem : rItems )
548                 {
549                     if ( rItem.mbSubSize )
550                     {
551                         long* pSize = &(rItem.mnPixSize);
552                         long  nTempErr;
553 
554                         if ( nErrorSum )
555                         {
556                             if ( nErrorSum < 0 )
557                                 nTempErr = -1;
558                             else
559                                 nTempErr = 1;
560                         }
561                         else
562                             nTempErr = 0;
563 
564                         if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 )
565                         {
566                             long nTemp = *pSize;
567                             if ( nTemp )
568                             {
569                                 *pSize -= nTemp;
570                                 nSizeDelta += nTemp;
571                             }
572                             nMins++;
573                         }
574                         else
575                         {
576                             *pSize += nCurSizeDelta;
577                             nSizeDelta -= nCurSizeDelta;
578                             if ( nTempErr && (*pSize || (nTempErr > 0)) )
579                             {
580                                 *pSize += nTempErr;
581                                 nSizeDelta -= nTempErr;
582                                 nErrorSum -= nTempErr;
583                             }
584                         }
585                     }
586                 }
587             }
588         }
589     }
590 
591     // calculate maximum size
592     if ( bRows )
593     {
594         nPos = nSetTop;
595         if ( !bDown )
596             nMaxPos = nSetTop-nSetHeight;
597         else
598             nMaxPos = nSetTop+nSetHeight;
599     }
600     else
601     {
602         nPos = nSetLeft;
603         if ( !bDown )
604             nMaxPos = nSetLeft-nSetWidth;
605         else
606             nMaxPos = nSetLeft+nSetWidth;
607     }
608 
609     // order windows and adept values
610     for ( size_t i = 0; i < nItems; i++ )
611     {
612         rItems[i].mnOldSplitPos    = rItems[i].mnSplitPos;
613         rItems[i].mnOldSplitSize   = rItems[i].mnSplitSize;
614         rItems[i].mnOldWidth       = rItems[i].mnWidth;
615         rItems[i].mnOldHeight      = rItems[i].mnHeight;
616 
617         bEmpty = false;
618         if ( bDown )
619         {
620             if ( nPos+rItems[i].mnPixSize > nMaxPos )
621                 bEmpty = true;
622         }
623         else
624         {
625             nPos -= rItems[i].mnPixSize;
626             if ( nPos < nMaxPos )
627                 bEmpty = true;
628         }
629 
630         if ( bEmpty )
631         {
632             rItems[i].mnWidth     = 0;
633             rItems[i].mnHeight    = 0;
634             rItems[i].mnSplitSize = 0;
635         }
636         else
637         {
638             if ( bRows )
639             {
640                 rItems[i].mnLeft   = nSetLeft;
641                 rItems[i].mnTop    = nPos;
642                 rItems[i].mnWidth  = nSetWidth;
643                 rItems[i].mnHeight = rItems[i].mnPixSize;
644             }
645             else
646             {
647                 rItems[i].mnLeft   = nPos;
648                 rItems[i].mnTop    = nSetTop;
649                 rItems[i].mnWidth  = rItems[i].mnPixSize;
650                 rItems[i].mnHeight = nSetHeight;
651             }
652 
653             if ( i > nItems-1 )
654                 rItems[i].mnSplitSize = 0;
655             else
656             {
657                 rItems[i].mnSplitSize = pSet->mnSplitSize;
658                 if ( bDown )
659                 {
660                     rItems[i].mnSplitPos  = nPos+rItems[i].mnPixSize;
661                     if ( rItems[i].mnSplitPos+rItems[i].mnSplitSize > nMaxPos )
662                         rItems[i].mnSplitSize = nMaxPos-rItems[i].mnSplitPos;
663                 }
664                 else
665                 {
666                     rItems[i].mnSplitPos = nPos-pSet->mnSplitSize;
667                     if ( rItems[i].mnSplitPos < nMaxPos )
668                         rItems[i].mnSplitSize = rItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos;
669                 }
670             }
671         }
672 
673         if ( !bDown )
674             nPos -= pSet->mnSplitSize;
675         else
676             nPos += rItems[i].mnPixSize+pSet->mnSplitSize;
677     }
678 
679     // calculate Sub-Set's
680     for ( auto& rItem : rItems )
681     {
682         if ( rItem.mpSet && rItem.mnWidth && rItem.mnHeight )
683         {
684             ImplCalcSet( rItem.mpSet.get(),
685                          rItem.mnLeft, rItem.mnTop,
686                          rItem.mnWidth, rItem.mnHeight,
687                          !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
688         }
689     }
690 
691     // set fixed
692     for ( auto& rItem : rItems )
693     {
694         rItem.mbFixed = false;
695         if ( rItem.mnBits & SplitWindowItemFlags::Fixed )
696             rItem.mbFixed = true;
697         else
698         {
699             // this item is also fixed if Child-Set is available,
700             // if a child is fixed
701             if ( rItem.mpSet )
702             {
703                 for ( auto const & j: rItem.mpSet->mvItems )
704                 {
705                     if ( j.mbFixed )
706                     {
707                         rItem.mbFixed = true;
708                         break;
709                     }
710                 }
711             }
712         }
713     }
714 }
715 
ImplCalcSet2(SplitWindow * pWindow,ImplSplitSet * pSet,bool bHide,bool bRows)716 void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, bool bHide,
717                                 bool bRows )
718 {
719     std::vector< ImplSplitItem >&     rItems = pSet->mvItems;
720 
721     if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate )
722     {
723         for ( const auto& rItem : rItems )
724         {
725             if ( rItem.mnSplitSize )
726             {
727                 // invalidate all, if applicable or only a small part
728                 if ( (rItem.mnOldSplitPos  != rItem.mnSplitPos)  ||
729                      (rItem.mnOldSplitSize != rItem.mnSplitSize) ||
730                      (rItem.mnOldWidth     != rItem.mnWidth)     ||
731                      (rItem.mnOldHeight    != rItem.mnHeight) )
732                 {
733                     tools::Rectangle aRect;
734 
735                     // invalidate old rectangle
736                     if ( bRows )
737                     {
738                         aRect.SetLeft( rItem.mnLeft );
739                         aRect.SetRight( rItem.mnLeft+rItem.mnOldWidth-1 );
740                         aRect.SetTop( rItem.mnOldSplitPos );
741                         aRect.SetBottom( aRect.Top() + rItem.mnOldSplitSize );
742                     }
743                     else
744                     {
745                         aRect.SetTop( rItem.mnTop );
746                         aRect.SetBottom( rItem.mnTop+rItem.mnOldHeight-1 );
747                         aRect.SetLeft( rItem.mnOldSplitPos );
748                         aRect.SetRight( aRect.Left() + rItem.mnOldSplitSize );
749                     }
750                     pWindow->Invalidate( aRect );
751                     // invalidate new rectangle
752                     if ( bRows )
753                     {
754                         aRect.SetLeft( rItem.mnLeft );
755                         aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
756                         aRect.SetTop( rItem.mnSplitPos );
757                         aRect.SetBottom( aRect.Top() + rItem.mnSplitSize );
758                     }
759                     else
760                     {
761                         aRect.SetTop( rItem.mnTop );
762                         aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
763                         aRect.SetLeft( rItem.mnSplitPos );
764                         aRect.SetRight( aRect.Left() + rItem.mnSplitSize );
765                     }
766                     pWindow->Invalidate( aRect );
767 
768                     // invalidate complete set, as these areas
769                     // are not cluttered by windows
770                     if ( rItem.mpSet && rItem.mpSet->mvItems.empty() )
771                     {
772                         aRect.SetLeft( rItem.mnLeft );
773                         aRect.SetTop( rItem.mnTop );
774                         aRect.SetRight( rItem.mnLeft+rItem.mnWidth-1 );
775                         aRect.SetBottom( rItem.mnTop+rItem.mnHeight-1 );
776                         pWindow->Invalidate( aRect );
777                     }
778                 }
779             }
780         }
781     }
782 
783     // position windows
784     for ( auto& rItem : rItems )
785     {
786         if ( rItem.mpSet )
787         {
788             bool bTempHide = bHide;
789             if ( !rItem.mnWidth || !rItem.mnHeight )
790                 bTempHide = true;
791             ImplCalcSet2( pWindow, rItem.mpSet.get(), bTempHide,
792                           !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
793         }
794         else
795         {
796             if ( rItem.mnWidth && rItem.mnHeight && !bHide )
797             {
798                 Point aPos( rItem.mnLeft, rItem.mnTop );
799                 Size  aSize( rItem.mnWidth, rItem.mnHeight );
800                 rItem.mpWindow->SetPosSizePixel( aPos, aSize );
801             }
802             else
803                 rItem.mpWindow->Hide();
804         }
805     }
806 
807     // show windows and reset flag
808     for ( auto& rItem : rItems )
809     {
810         if ( rItem.mpWindow && rItem.mnWidth && rItem.mnHeight && !bHide )
811             rItem.mpWindow->Show();
812     }
813 }
814 
ImplCalcLogSize(std::vector<ImplSplitItem> & rItems,size_t nItems)815 static void ImplCalcLogSize( std::vector< ImplSplitItem > & rItems, size_t nItems )
816 {
817     // update original sizes
818     size_t  i;
819     long    nRelSize = 0;
820     long    nPerSize = 0;
821 
822     for ( i = 0; i < nItems; i++ )
823     {
824         if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
825             nRelSize += rItems[i].mnPixSize;
826         else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
827             nPerSize += rItems[i].mnPixSize;
828     }
829     nPerSize += nRelSize;
830     for ( i = 0; i < nItems; i++ )
831     {
832         if ( rItems[i].mnBits & SplitWindowItemFlags::RelativeSize )
833         {
834             if ( nRelSize )
835                 rItems[i].mnSize = (rItems[i].mnPixSize+(nRelSize/2))/nRelSize;
836             else
837                 rItems[i].mnSize = 1;
838         }
839         else if ( rItems[i].mnBits & SplitWindowItemFlags::PercentSize )
840         {
841             if ( nPerSize )
842                 rItems[i].mnSize = (rItems[i].mnPixSize*100)/nPerSize;
843             else
844                 rItems[i].mnSize = 1;
845         }
846         else
847             rItems[i].mnSize = rItems[i].mnPixSize;
848     }
849 }
850 
ImplDrawBack(vcl::RenderContext & rRenderContext,ImplSplitSet * pSet)851 void SplitWindow::ImplDrawBack(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet)
852 {
853     std::vector< ImplSplitItem >& rItems = pSet->mvItems;
854 
855     for ( const auto& rItem : rItems )
856     {
857         pSet = rItem.mpSet.get();
858         if (pSet && pSet->mpWallpaper)
859         {
860             Point aPoint(rItem.mnLeft, rItem.mnTop);
861             Size aSize(rItem.mnWidth, rItem.mnHeight);
862             tools::Rectangle aRect(aPoint, aSize);
863             rRenderContext.DrawWallpaper(aRect, *pSet->mpWallpaper);
864         }
865     }
866 
867     for ( auto& rItem : rItems )
868     {
869         if (rItem.mpSet)
870             ImplDrawBack(rRenderContext, rItem.mpSet.get());
871     }
872 }
873 
ImplDrawSplit(vcl::RenderContext & rRenderContext,ImplSplitSet * pSet,bool bRows,bool bDown)874 static void ImplDrawSplit(vcl::RenderContext& rRenderContext, ImplSplitSet* pSet, bool bRows, bool bDown)
875 {
876     if (pSet->mvItems.empty())
877         return;
878 
879     size_t     nItems = pSet->mvItems.size();
880     long       nPos;
881     long       nTop;
882     long       nBottom;
883     std::vector< ImplSplitItem >& rItems = pSet->mvItems;
884     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
885 
886     for (size_t i = 0; i < nItems-1; i++)
887     {
888         if (rItems[i].mnSplitSize)
889         {
890             nPos = rItems[i].mnSplitPos;
891 
892             long nItemSplitSize = rItems[i].mnSplitSize;
893             long nSplitSize = pSet->mnSplitSize;
894             if (bRows)
895             {
896                 nTop    = rItems[i].mnLeft;
897                 nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
898 
899                 if (bDown || (nItemSplitSize >= nSplitSize))
900                 {
901                     rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
902                     rRenderContext.DrawLine(Point(nTop, nPos + 1), Point(nBottom, nPos + 1));
903                 }
904                 nPos += nSplitSize-2;
905                 if ((!bDown && (nItemSplitSize >= 2)) ||
906                     (bDown  && (nItemSplitSize >= nSplitSize - 1)))
907                 {
908                     rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
909                     rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
910                 }
911                 nPos++;
912                 if (!bDown || (nItemSplitSize >= nSplitSize))
913                 {
914                     rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
915                     rRenderContext.DrawLine(Point(nTop, nPos), Point(nBottom, nPos));
916                 }
917             }
918             else
919             {
920                 nTop    = rItems[i].mnTop;
921                 nBottom = rItems[i].mnTop+pSet->mvItems[i].mnHeight-1;
922 
923                 if (bDown || (nItemSplitSize >= nSplitSize))
924                 {
925                     rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
926                     rRenderContext.DrawLine(Point(nPos + 1, nTop), Point(nPos+1, nBottom));
927                 }
928                 nPos += pSet->mnSplitSize - 2;
929                 if ((!bDown && (nItemSplitSize >= 2)) ||
930                     (bDown  && (nItemSplitSize >= nSplitSize - 1)))
931                 {
932                     rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
933                     rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
934                 }
935                 nPos++;
936                 if (!bDown || (nItemSplitSize >= nSplitSize))
937                 {
938                     rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
939                     rRenderContext.DrawLine(Point(nPos, nTop), Point(nPos, nBottom));
940                 }
941             }
942         }
943     }
944 
945     for ( auto& rItem : rItems )
946     {
947         if (rItem.mpSet && rItem.mnWidth && rItem.mnHeight)
948         {
949             ImplDrawSplit(rRenderContext, rItem.mpSet.get(), !(rItem.mnBits & SplitWindowItemFlags::ColSet), true/*bDown*/);
950         }
951     }
952 }
953 
ImplTestSplit(ImplSplitSet * pSet,const Point & rPos,long & rMouseOff,ImplSplitSet ** ppFoundSet,sal_uInt16 & rFoundPos,bool bRows)954 sal_uInt16 SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
955                                    long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos,
956                                    bool bRows )
957 {
958     if ( pSet->mvItems.empty() )
959         return 0;
960 
961     sal_uInt16      nSplitTest;
962     size_t          nItems = pSet->mvItems.size();
963     long            nMPos1;
964     long            nMPos2;
965     long            nPos;
966     long            nTop;
967     long            nBottom;
968     std::vector< ImplSplitItem >& rItems = pSet->mvItems;
969 
970     if ( bRows )
971     {
972         nMPos1 = rPos.X();
973         nMPos2 = rPos.Y();
974     }
975     else
976     {
977         nMPos1 = rPos.Y();
978         nMPos2 = rPos.X();
979     }
980 
981     for ( size_t i = 0; i < nItems-1; i++ )
982     {
983         if ( rItems[i].mnSplitSize )
984         {
985             if ( bRows )
986             {
987                 nTop    = rItems[i].mnLeft;
988                 nBottom = rItems[i].mnLeft+rItems[i].mnWidth-1;
989             }
990             else
991             {
992                 nTop    = rItems[i].mnTop;
993                 nBottom = rItems[i].mnTop+rItems[i].mnHeight-1;
994             }
995             nPos = rItems[i].mnSplitPos;
996 
997             if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) &&
998                  (nMPos2 >= nPos) && (nMPos2 <= nPos+rItems[i].mnSplitSize) )
999             {
1000                 if ( !rItems[i].mbFixed && !rItems[i+1].mbFixed )
1001                 {
1002                     rMouseOff = nMPos2-nPos;
1003                     *ppFoundSet = pSet;
1004                     rFoundPos = i;
1005                     if ( bRows )
1006                         return SPLIT_VERT;
1007                     else
1008                         return SPLIT_HORZ;
1009                 }
1010                 else
1011                     return SPLIT_NOSPLIT;
1012             }
1013         }
1014     }
1015 
1016     for ( auto& rItem : rItems )
1017     {
1018         if ( rItem.mpSet )
1019         {
1020             nSplitTest = ImplTestSplit( rItem.mpSet.get(), rPos,
1021                                        rMouseOff, ppFoundSet, rFoundPos,
1022                                        !(rItem.mnBits & SplitWindowItemFlags::ColSet) );
1023             if ( nSplitTest )
1024                 return nSplitTest;
1025         }
1026     }
1027 
1028     return 0;
1029 }
1030 
ImplTestSplit(const SplitWindow * pWindow,const Point & rPos,long & rMouseOff,ImplSplitSet ** ppFoundSet,sal_uInt16 & rFoundPos)1031 sal_uInt16 SplitWindow::ImplTestSplit( const SplitWindow* pWindow, const Point& rPos,
1032                                    long& rMouseOff, ImplSplitSet** ppFoundSet, sal_uInt16& rFoundPos )
1033 {
1034     // Resizable SplitWindow should be treated different
1035     if ( pWindow->mnWinStyle & WB_SIZEABLE )
1036     {
1037         long    nTPos;
1038         long    nPos;
1039         long    nBorder;
1040 
1041         if ( pWindow->mbHorz )
1042         {
1043             if ( pWindow->mbBottomRight )
1044             {
1045                 nBorder = pWindow->mnBottomBorder;
1046                 nPos = 0;
1047             }
1048             else
1049             {
1050                 nBorder = pWindow->mnTopBorder;
1051                 nPos = pWindow->mnDY-nBorder;
1052             }
1053             nTPos = rPos.Y();
1054         }
1055         else
1056         {
1057             if ( pWindow->mbBottomRight )
1058             {
1059                 nBorder = pWindow->mnRightBorder;
1060                 nPos = 0;
1061             }
1062             else
1063             {
1064                 nBorder = pWindow->mnLeftBorder;
1065                 nPos = pWindow->mnDX-nBorder;
1066             }
1067             nTPos = rPos.X();
1068         }
1069         long nSplitSize = pWindow->mpMainSet->mnSplitSize-2;
1070         if (pWindow->mbFadeOut)
1071             nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1072         if ( !pWindow->mbBottomRight )
1073             nPos -= nSplitSize;
1074         if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) )
1075         {
1076             rMouseOff = nTPos-nPos;
1077             *ppFoundSet = pWindow->mpMainSet.get();
1078             if ( !pWindow->mpMainSet->mvItems.empty() )
1079                 rFoundPos = pWindow->mpMainSet->mvItems.size() - 1;
1080             else
1081                 rFoundPos = 0;
1082             if ( pWindow->mbHorz )
1083                 return SPLIT_VERT | SPLIT_WINDOW;
1084             else
1085                 return SPLIT_HORZ | SPLIT_WINDOW;
1086         }
1087     }
1088 
1089     return ImplTestSplit( pWindow->mpMainSet.get(), rPos, rMouseOff, ppFoundSet, rFoundPos,
1090                          pWindow->mbHorz );
1091 }
1092 
ImplDrawSplitTracking(const Point & rPos)1093 void SplitWindow::ImplDrawSplitTracking(const Point& rPos)
1094 {
1095     tools::Rectangle aRect;
1096 
1097     if (mnSplitTest & SPLIT_HORZ)
1098     {
1099         aRect.SetTop( maDragRect.Top() );
1100         aRect.SetBottom( maDragRect.Bottom() );
1101         aRect.SetLeft( rPos.X() );
1102         aRect.SetRight( aRect.Left() + mpSplitSet->mnSplitSize - 1 );
1103         if (!(mnWinStyle & WB_NOSPLITDRAW))
1104             aRect.AdjustRight( -1 );
1105         if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
1106         {
1107             aRect.AdjustLeft(SPLITWIN_SPLITSIZEEXLN );
1108             aRect.AdjustRight(SPLITWIN_SPLITSIZEEXLN );
1109         }
1110     }
1111     else
1112     {
1113         aRect.SetLeft( maDragRect.Left() );
1114         aRect.SetRight( maDragRect.Right() );
1115         aRect.SetTop( rPos.Y() );
1116         aRect.SetBottom( aRect.Top() + mpSplitSet->mnSplitSize - 1 );
1117         if (!(mnWinStyle & WB_NOSPLITDRAW))
1118             aRect.AdjustBottom( -1 );
1119         if ((mnSplitTest & SPLIT_WINDOW) && mbFadeOut)
1120         {
1121             aRect.AdjustTop(SPLITWIN_SPLITSIZEEXLN );
1122             aRect.AdjustBottom(SPLITWIN_SPLITSIZEEXLN );
1123         }
1124     }
1125     ShowTracking(aRect, ShowTrackFlags::Split);
1126 }
1127 
ImplInit(vcl::Window * pParent,WinBits nStyle)1128 void SplitWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
1129 {
1130     mpMainSet.reset(new ImplSplitSet());
1131     mpBaseSet               = mpMainSet.get();
1132     mpSplitSet              = nullptr;
1133     mpLastSizes             = nullptr;
1134     mnDX                    = 0;
1135     mnDY                    = 0;
1136     mnLeftBorder            = 0;
1137     mnTopBorder             = 0;
1138     mnRightBorder           = 0;
1139     mnBottomBorder          = 0;
1140     mnMaxSize               = 0;
1141     mnMouseOff              = 0;
1142     meAlign                 = WindowAlign::Top;
1143     mnWinStyle              = nStyle;
1144     mnSplitTest             = 0;
1145     mnSplitPos              = 0;
1146     mnMouseModifier         = 0;
1147     mnMStartPos             = 0;
1148     mnMSplitPos             = 0;
1149     mbDragFull              = false;
1150     mbHorz                  = true;
1151     mbBottomRight           = false;
1152     mbCalc                  = false;
1153     mbRecalc                = true;
1154     mbInvalidate            = true;
1155     mbFadeIn                = false;
1156     mbFadeOut               = false;
1157     mbFadeInDown            = false;
1158     mbFadeOutDown           = false;
1159     mbFadeInPressed         = false;
1160     mbFadeOutPressed        = false;
1161     mbFadeNoButtonMode      = false;
1162 
1163     if ( nStyle & WB_NOSPLITDRAW )
1164     {
1165         mpMainSet->mnSplitSize -= 2;
1166         mbInvalidate = false;
1167     }
1168 
1169     if ( nStyle & WB_BORDER )
1170     {
1171         ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
1172                         mnRightBorder, mnBottomBorder );
1173     }
1174     else
1175     {
1176         mnLeftBorder   = 0;
1177         mnTopBorder    = 0;
1178         mnRightBorder  = 0;
1179         mnBottomBorder = 0;
1180     }
1181 
1182     DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) );
1183 
1184     ImplInitSettings();
1185 }
1186 
ImplInitSettings()1187 void SplitWindow::ImplInitSettings()
1188 {
1189     // If MainSet has a Wallpaper, this is the background,
1190     // otherwise it is the standard colour
1191     if ( mpMainSet->mpWallpaper )
1192         SetBackground( *mpMainSet->mpWallpaper );
1193     else
1194     {
1195         const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1196 
1197         Color aColor;
1198         if ( IsControlBackground() )
1199             aColor = GetControlBackground();
1200         else if ( Window::GetStyle() & WB_3DLOOK )
1201             aColor = rStyleSettings.GetFaceColor();
1202         else
1203             aColor = rStyleSettings.GetWindowColor();
1204         SetBackground( aColor );
1205     }
1206 }
1207 
SplitWindow(vcl::Window * pParent,WinBits nStyle)1208 SplitWindow::SplitWindow( vcl::Window* pParent, WinBits nStyle ) :
1209     DockingWindow( WindowType::SPLITWINDOW )
1210 {
1211     ImplInit( pParent, nStyle );
1212     DockingWindow::SetIdleDebugName( "vcl::SplitWindow maLayoutIdle" );
1213 }
1214 
~SplitWindow()1215 SplitWindow::~SplitWindow()
1216 {
1217     disposeOnce();
1218 }
1219 
dispose()1220 void SplitWindow::dispose()
1221 {
1222     // delete Sets
1223     mpMainSet.reset();
1224     DockingWindow::dispose();
1225 }
1226 
ImplSetWindowSize(long nDelta)1227 void SplitWindow::ImplSetWindowSize( long nDelta )
1228 {
1229     if ( !nDelta )
1230         return;
1231 
1232     Size aSize = GetSizePixel();
1233     switch ( meAlign )
1234     {
1235     case WindowAlign::Top:
1236         aSize.AdjustHeight(nDelta );
1237         SetSizePixel( aSize );
1238         break;
1239     case WindowAlign::Bottom:
1240     {
1241         maDragRect.AdjustTop(nDelta );
1242         Point aPos = GetPosPixel();
1243         aPos.AdjustY( -nDelta );
1244         aSize.AdjustHeight(nDelta );
1245         SetPosSizePixel( aPos, aSize );
1246         break;
1247     }
1248     case WindowAlign::Left:
1249         aSize.AdjustWidth(nDelta );
1250         SetSizePixel( aSize );
1251         break;
1252     case WindowAlign::Right:
1253     default:
1254     {
1255         maDragRect.AdjustLeft(nDelta );
1256         Point aPos = GetPosPixel();
1257         aPos.AdjustX( -nDelta );
1258         aSize.AdjustWidth(nDelta );
1259         SetPosSizePixel( aPos, aSize );
1260         break;
1261     }
1262     }
1263 
1264     SplitResize();
1265 }
1266 
CalcLayoutSizePixel(const Size & aNewSize)1267 Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize )
1268 {
1269     Size aSize( aNewSize );
1270     long nSplitSize = mpMainSet->mnSplitSize-2;
1271 
1272     if (mbFadeOut)
1273         nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1274 
1275     // if the window is sizeable and if it does not contain a relative window,
1276     // the size is determined according to MainSet
1277     if ( mnWinStyle & WB_SIZEABLE )
1278     {
1279         long    nCalcSize = 0;
1280         std::vector< ImplSplitItem* >::size_type i;
1281 
1282         for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
1283         {
1284             if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
1285                 break;
1286             else
1287                 nCalcSize += mpMainSet->mvItems[i].mnSize;
1288         }
1289 
1290         if ( i == mpMainSet->mvItems.size() )
1291         {
1292             long    nDelta = 0;
1293             long    nCurSize;
1294 
1295             if ( mbHorz )
1296                 nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder;
1297             else
1298                 nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder;
1299             nCurSize -= nSplitSize;
1300             nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
1301 
1302             nDelta = nCalcSize-nCurSize;
1303             if ( !nDelta )
1304                 return aSize;
1305 
1306             switch ( meAlign )
1307             {
1308             case WindowAlign::Top:
1309                 aSize.AdjustHeight(nDelta );
1310                 break;
1311             case WindowAlign::Bottom:
1312                 aSize.AdjustHeight(nDelta );
1313                 break;
1314             case WindowAlign::Left:
1315                 aSize.AdjustWidth(nDelta );
1316                 break;
1317             case WindowAlign::Right:
1318             default:
1319                 aSize.AdjustWidth(nDelta );
1320                 break;
1321             }
1322         }
1323     }
1324 
1325     return aSize;
1326 }
1327 
ImplCalcLayout()1328 void SplitWindow::ImplCalcLayout()
1329 {
1330     if ( !mbCalc || !mbRecalc || mpMainSet->mvItems.empty() )
1331         return;
1332 
1333     long nSplitSize = mpMainSet->mnSplitSize-2;
1334     if (mbFadeOut)
1335         nSplitSize += SPLITWIN_SPLITSIZEEXLN;
1336 
1337     // if the window is sizeable and if it does not contain a relative window,
1338     // the size is determined according to MainSet
1339     if ( mnWinStyle & WB_SIZEABLE )
1340     {
1341         long    nCalcSize = 0;
1342         std::vector<ImplSplitItem *>::size_type i;
1343 
1344         for ( i = 0; i < mpMainSet->mvItems.size(); i++ )
1345         {
1346             if ( mpMainSet->mvItems[i].mnBits & (SplitWindowItemFlags::RelativeSize | SplitWindowItemFlags::PercentSize) )
1347                 break;
1348             else
1349                 nCalcSize += mpMainSet->mvItems[i].mnSize;
1350         }
1351 
1352         if ( i == mpMainSet->mvItems.size() )
1353         {
1354             long    nCurSize;
1355             if ( mbHorz )
1356                 nCurSize = mnDY-mnTopBorder-mnBottomBorder;
1357             else
1358                 nCurSize = mnDX-mnLeftBorder-mnRightBorder;
1359             nCurSize -= nSplitSize;
1360             nCurSize -= (mpMainSet->mvItems.size()-1)*mpMainSet->mnSplitSize;
1361 
1362             mbRecalc = false;
1363             ImplSetWindowSize( nCalcSize-nCurSize );
1364             mbRecalc = true;
1365         }
1366     }
1367 
1368     if ( (mnDX <= 0) || (mnDY <= 0) )
1369         return;
1370 
1371     // pre-calculate sizes/position
1372     long    nL;
1373     long    nT;
1374     long    nW;
1375     long    nH;
1376 
1377     if ( mbHorz )
1378     {
1379         if ( mbBottomRight )
1380             nT = mnDY-mnBottomBorder;
1381         else
1382             nT = mnTopBorder;
1383         nL = mnLeftBorder;
1384     }
1385     else
1386     {
1387         if ( mbBottomRight )
1388             nL = mnDX-mnRightBorder;
1389         else
1390             nL = mnLeftBorder;
1391         nT = mnTopBorder;
1392     }
1393     nW = mnDX-mnLeftBorder-mnRightBorder;
1394     nH = mnDY-mnTopBorder-mnBottomBorder;
1395     if ( mnWinStyle & WB_SIZEABLE )
1396     {
1397         if ( mbHorz )
1398             nH -= nSplitSize;
1399         else
1400             nW -= nSplitSize;
1401     }
1402 
1403     // calculate sets recursive
1404     ImplCalcSet( mpMainSet.get(), nL, nT, nW, nH, mbHorz, !mbBottomRight );
1405     ImplCalcSet2( this, mpMainSet.get(), false, mbHorz );
1406     mbCalc = false;
1407 }
1408 
ImplUpdate()1409 void SplitWindow::ImplUpdate()
1410 {
1411     mbCalc = true;
1412 
1413     if ( IsReallyShown() && IsUpdateMode() && mbRecalc )
1414     {
1415         if ( !mpMainSet->mvItems.empty() )
1416             ImplCalcLayout();
1417         else
1418             Invalidate();
1419     }
1420 }
1421 
ImplSplitMousePos(Point & rMousePos)1422 void SplitWindow::ImplSplitMousePos( Point& rMousePos )
1423 {
1424     if ( mnSplitTest & SPLIT_HORZ )
1425     {
1426         rMousePos.AdjustX( -mnMouseOff );
1427         if ( rMousePos.X() < maDragRect.Left() )
1428             rMousePos.setX( maDragRect.Left() );
1429         else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() )
1430             rMousePos.setX( maDragRect.Right()-mpSplitSet->mnSplitSize+1 );
1431         // store in screen coordinates due to FullDrag
1432         mnMSplitPos = OutputToScreenPixel( rMousePos ).X();
1433     }
1434     else
1435     {
1436         rMousePos.AdjustY( -mnMouseOff );
1437         if ( rMousePos.Y() < maDragRect.Top() )
1438             rMousePos.setY( maDragRect.Top() );
1439         else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() )
1440             rMousePos.setY( maDragRect.Bottom()-mpSplitSet->mnSplitSize+1 );
1441         mnMSplitPos = OutputToScreenPixel( rMousePos ).Y();
1442     }
1443 }
1444 
ImplGetButtonRect(tools::Rectangle & rRect,bool bTest) const1445 void SplitWindow::ImplGetButtonRect( tools::Rectangle& rRect, bool bTest ) const
1446 {
1447     long nSplitSize = mpMainSet->mnSplitSize-1;
1448     if (mbFadeOut || mbFadeIn)
1449         nSplitSize += SPLITWIN_SPLITSIZEEX;
1450 
1451     long nButtonSize = 0;
1452     if ( mbFadeIn )
1453         nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
1454     if ( mbFadeOut )
1455         nButtonSize += SPLITWIN_SPLITSIZEFADE+1;
1456     long nCenterEx = 0;
1457     if ( mbHorz )
1458         nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2;
1459     else
1460         nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2;
1461     long nEx = 0;
1462     if ( nCenterEx > 0 )
1463         nEx += nCenterEx;
1464 
1465     switch ( meAlign )
1466     {
1467     case WindowAlign::Top:
1468         rRect.SetLeft( mnLeftBorder+nEx );
1469         rRect.SetTop( mnDY-mnBottomBorder-nSplitSize );
1470         rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
1471         rRect.SetBottom( mnDY-mnBottomBorder-1 );
1472         if ( bTest )
1473         {
1474             rRect.AdjustTop( -mnTopBorder );
1475             rRect.AdjustBottom(mnBottomBorder );
1476         }
1477         break;
1478     case WindowAlign::Bottom:
1479         rRect.SetLeft( mnLeftBorder+nEx );
1480         rRect.SetTop( mnTopBorder );
1481         rRect.SetRight( rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE );
1482         rRect.SetBottom( mnTopBorder+nSplitSize-1 );
1483         if ( bTest )
1484         {
1485             rRect.AdjustTop( -mnTopBorder );
1486             rRect.AdjustBottom(mnBottomBorder );
1487         }
1488         break;
1489     case WindowAlign::Left:
1490         rRect.SetLeft( mnDX-mnRightBorder-nSplitSize );
1491         rRect.SetTop( mnTopBorder+nEx );
1492         rRect.SetRight( mnDX-mnRightBorder-1 );
1493         rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
1494         if ( bTest )
1495         {
1496             rRect.AdjustLeft( -mnLeftBorder );
1497             rRect.AdjustRight(mnRightBorder );
1498         }
1499         break;
1500     case WindowAlign::Right:
1501         rRect.SetLeft( mnLeftBorder );
1502         rRect.SetTop( mnTopBorder+nEx );
1503         rRect.SetRight( mnLeftBorder+nSplitSize-1 );
1504         rRect.SetBottom( rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE );
1505         if ( bTest )
1506         {
1507             rRect.AdjustLeft( -mnLeftBorder );
1508             rRect.AdjustRight(mnRightBorder );
1509         }
1510         break;
1511     }
1512 }
1513 
ImplGetFadeInRect(tools::Rectangle & rRect,bool bTest) const1514 void SplitWindow::ImplGetFadeInRect( tools::Rectangle& rRect, bool bTest ) const
1515 {
1516     tools::Rectangle aRect;
1517 
1518     if ( mbFadeIn )
1519         ImplGetButtonRect( aRect, bTest );
1520 
1521     rRect = aRect;
1522 }
1523 
ImplGetFadeOutRect(tools::Rectangle & rRect) const1524 void SplitWindow::ImplGetFadeOutRect( tools::Rectangle& rRect ) const
1525 {
1526     tools::Rectangle aRect;
1527 
1528     if ( mbFadeOut )
1529         ImplGetButtonRect( aRect, false );
1530 
1531     rRect = aRect;
1532 }
1533 
ImplDrawGrip(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect,bool bHorizontal,bool bLeft)1534 void SplitWindow::ImplDrawGrip(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bHorizontal, bool bLeft)
1535 {
1536     const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1537 
1538     Color aColor;
1539 
1540     if (rRect.IsInside(GetPointerPosPixel()))
1541     {
1542         vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, rRect, 2, false, false, false);
1543 
1544         aColor = rStyleSettings.GetDarkShadowColor();
1545     }
1546     else
1547     {
1548         rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
1549         rRenderContext.SetFillColor(rStyleSettings.GetDarkShadowColor());
1550 
1551         rRenderContext.DrawRect(rRect);
1552 
1553         aColor = rStyleSettings.GetFaceColor();
1554     }
1555 
1556     AntialiasingFlags nAA = rRenderContext.GetAntialiasing();
1557     rRenderContext.SetAntialiasing(nAA | AntialiasingFlags::PixelSnapHairline | AntialiasingFlags::EnableB2dDraw);
1558 
1559     long nWidth = rRect.getWidth();
1560     long nWidthHalf = nWidth / 2;
1561     long nHeight = rRect.getHeight();
1562     long nHeightHalf = nHeight / 2;
1563 
1564     long nLeft = rRect.Left();
1565     long nRight = rRect.Right();
1566     long nTop = rRect.Top();
1567     long nBottom = rRect.Bottom();
1568     long nMargin = 1;
1569 
1570     rRenderContext.SetLineColor(aColor);
1571     rRenderContext.SetFillColor(aColor);
1572 
1573     tools::Polygon aPoly(3);
1574 
1575     if (bHorizontal)
1576     {
1577         long nCenter = nLeft + nWidthHalf;
1578 
1579         if (bLeft)
1580         {
1581             aPoly.SetPoint(Point(nCenter,               nTop    + nMargin), 0);
1582             aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 1);
1583             aPoly.SetPoint(Point(nCenter - nHeightHalf, nBottom - nMargin), 2);
1584         }
1585         else
1586         {
1587             aPoly.SetPoint(Point(nCenter,               nBottom - nMargin), 0);
1588             aPoly.SetPoint(Point(nCenter - nHeightHalf, nTop    + nMargin), 1);
1589             aPoly.SetPoint(Point(nCenter + nHeightHalf, nTop    + nMargin), 2);
1590         }
1591         rRenderContext.DrawPolygon(aPoly);
1592     }
1593     else
1594     {
1595         long nCenter = nTop + nHeightHalf;
1596 
1597         if (bLeft)
1598         {
1599             aPoly.SetPoint(Point(nLeft  + nMargin, nCenter), 0);
1600             aPoly.SetPoint(Point(nRight - nMargin, nCenter - nWidthHalf), 1);
1601             aPoly.SetPoint(Point(nRight - nMargin, nCenter + nWidthHalf), 2);
1602         }
1603         else
1604         {
1605             aPoly.SetPoint(Point(nRight - nMargin, nCenter), 0);
1606             aPoly.SetPoint(Point(nLeft  + nMargin, nCenter - nWidthHalf), 1);
1607             aPoly.SetPoint(Point(nLeft  + nMargin, nCenter + nWidthHalf), 2);
1608         }
1609         rRenderContext.DrawPolygon(aPoly);
1610     }
1611 
1612     rRenderContext.SetAntialiasing(nAA);
1613 }
1614 
ImplDrawFadeIn(vcl::RenderContext & rRenderContext)1615 void SplitWindow::ImplDrawFadeIn(vcl::RenderContext& rRenderContext)
1616 {
1617     if (mbFadeIn)
1618     {
1619         tools::Rectangle aTempRect;
1620         ImplGetFadeInRect(aTempRect);
1621 
1622         bool bLeft = true;
1623         switch (meAlign)
1624         {
1625         case WindowAlign::Top:
1626         case WindowAlign::Left:
1627             bLeft = false;
1628             break;
1629         case WindowAlign::Bottom:
1630         case WindowAlign::Right:
1631         default:
1632             bLeft = true;
1633             break;
1634         }
1635 
1636         ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
1637     }
1638 }
1639 
ImplDrawFadeOut(vcl::RenderContext & rRenderContext)1640 void SplitWindow::ImplDrawFadeOut(vcl::RenderContext& rRenderContext)
1641 {
1642     if (mbFadeOut)
1643     {
1644         tools::Rectangle aTempRect;
1645         ImplGetFadeOutRect(aTempRect);
1646 
1647         bool bLeft = true;
1648         switch (meAlign)
1649         {
1650         case WindowAlign::Bottom:
1651         case WindowAlign::Right:
1652             bLeft = false;
1653             break;
1654         case WindowAlign::Top:
1655         case WindowAlign::Left:
1656         default:
1657             bLeft = true;
1658             break;
1659         }
1660 
1661         ImplDrawGrip(rRenderContext, aTempRect, (meAlign == WindowAlign::Top) || (meAlign == WindowAlign::Bottom), bLeft);
1662     }
1663 }
1664 
ImplStartSplit(const MouseEvent & rMEvt)1665 void SplitWindow::ImplStartSplit( const MouseEvent& rMEvt )
1666 {
1667     Point aMousePosPixel = rMEvt.GetPosPixel();
1668     mnSplitTest = ImplTestSplit( this, aMousePosPixel, mnMouseOff, &mpSplitSet, mnSplitPos );
1669 
1670     if ( !mnSplitTest || (mnSplitTest & SPLIT_NOSPLIT) )
1671         return;
1672 
1673     ImplSplitItem*  pSplitItem;
1674     long            nCurMaxSize;
1675     bool            bPropSmaller;
1676 
1677     mnMouseModifier = rMEvt.GetModifier();
1678     bPropSmaller = (mnMouseModifier & KEY_SHIFT) && (static_cast<sal_uInt16>(mnSplitPos+1) < mpSplitSet->mvItems.size());
1679 
1680     // here we can set the maximum size
1681     StartSplit();
1682 
1683     if ( mnMaxSize )
1684         nCurMaxSize = mnMaxSize;
1685     else
1686     {
1687         Size aSize = GetParent()->GetOutputSizePixel();
1688         if ( mbHorz )
1689             nCurMaxSize = aSize.Height();
1690         else
1691             nCurMaxSize = aSize.Width();
1692     }
1693 
1694     if ( !mpSplitSet->mvItems.empty() )
1695     {
1696         bool bDown = true;
1697         if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
1698             bDown = false;
1699 
1700         pSplitItem          = &mpSplitSet->mvItems[mnSplitPos];
1701         maDragRect.SetLeft( pSplitItem->mnLeft );
1702         maDragRect.SetTop( pSplitItem->mnTop );
1703         maDragRect.SetRight( pSplitItem->mnLeft+pSplitItem->mnWidth-1 );
1704         maDragRect.SetBottom( pSplitItem->mnTop+pSplitItem->mnHeight-1 );
1705 
1706         if ( mnSplitTest & SPLIT_HORZ )
1707         {
1708             if ( bDown )
1709                 maDragRect.AdjustRight(mpSplitSet->mnSplitSize );
1710             else
1711                 maDragRect.AdjustLeft( -(mpSplitSet->mnSplitSize) );
1712         }
1713         else
1714         {
1715             if ( bDown )
1716                 maDragRect.AdjustBottom(mpSplitSet->mnSplitSize );
1717             else
1718                 maDragRect.AdjustTop( -(mpSplitSet->mnSplitSize) );
1719         }
1720 
1721         if ( mnSplitPos )
1722         {
1723             long nTemp = mnSplitPos;
1724             while ( nTemp )
1725             {
1726                 pSplitItem = &mpSplitSet->mvItems[nTemp-1];
1727                 if ( pSplitItem->mbFixed )
1728                     break;
1729                 else
1730                 {
1731                     if ( mnSplitTest & SPLIT_HORZ )
1732                     {
1733                         if ( bDown )
1734                             maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
1735                         else
1736                             maDragRect.AdjustRight(pSplitItem->mnPixSize );
1737                     }
1738                     else
1739                     {
1740                         if ( bDown )
1741                             maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
1742                         else
1743                             maDragRect.AdjustBottom(pSplitItem->mnPixSize );
1744                     }
1745                 }
1746                 nTemp--;
1747             }
1748         }
1749 
1750         if ( (mpSplitSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) && !bPropSmaller )
1751         {
1752             if ( bDown )
1753             {
1754                 if ( mbHorz )
1755                     maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
1756                 else
1757                     maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
1758             }
1759             else
1760             {
1761                 if ( mbHorz )
1762                     maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
1763                 else
1764                     maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
1765             }
1766         }
1767         else
1768         {
1769             std::vector<ImplSplitItem *>::size_type nTemp = mnSplitPos+1;
1770             while ( nTemp < mpSplitSet->mvItems.size() )
1771             {
1772                 pSplitItem = &mpSplitSet->mvItems[nTemp];
1773                 if ( pSplitItem->mbFixed )
1774                     break;
1775                 else
1776                 {
1777                     if ( mnSplitTest & SPLIT_HORZ )
1778                     {
1779                         if ( bDown )
1780                             maDragRect.AdjustRight(pSplitItem->mnPixSize );
1781                         else
1782                             maDragRect.AdjustLeft( -(pSplitItem->mnPixSize) );
1783                     }
1784                     else
1785                     {
1786                         if ( bDown )
1787                             maDragRect.AdjustBottom(pSplitItem->mnPixSize );
1788                         else
1789                             maDragRect.AdjustTop( -(pSplitItem->mnPixSize) );
1790                     }
1791                 }
1792                 nTemp++;
1793             }
1794         }
1795     }
1796     else
1797     {
1798         maDragRect.SetLeft( mnLeftBorder );
1799         maDragRect.SetTop( mnTopBorder );
1800         maDragRect.SetRight( mnDX-mnRightBorder-1 );
1801         maDragRect.SetBottom( mnDY-mnBottomBorder-1 );
1802         if ( mbHorz )
1803         {
1804             if ( mbBottomRight )
1805                 maDragRect.AdjustTop( -(nCurMaxSize-mnDY-mnBottomBorder) );
1806             else
1807                 maDragRect.AdjustBottom(nCurMaxSize-mnDY-mnTopBorder );
1808         }
1809         else
1810         {
1811             if ( mbBottomRight )
1812                 maDragRect.AdjustLeft( -(nCurMaxSize-mnDX-mnRightBorder) );
1813             else
1814                 maDragRect.AdjustRight(nCurMaxSize-mnDX-mnLeftBorder );
1815         }
1816     }
1817 
1818     StartTracking();
1819 
1820     mbDragFull = bool(GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Split);
1821 
1822     ImplSplitMousePos( aMousePosPixel );
1823 
1824     if (!mbDragFull)
1825     {
1826         ImplDrawSplitTracking(aMousePosPixel);
1827     }
1828     else
1829     {
1830         std::vector< ImplSplitItem >&  rItems = mpSplitSet->mvItems;
1831         sal_uInt16       nItems = mpSplitSet->mvItems.size();
1832         mpLastSizes = new long[nItems*2];
1833         for ( sal_uInt16 i = 0; i < nItems; i++ )
1834         {
1835             mpLastSizes[i*2]   = rItems[i].mnSize;
1836             mpLastSizes[i*2+1] = rItems[i].mnPixSize;
1837         }
1838     }
1839     mnMStartPos = mnMSplitPos;
1840 
1841     PointerStyle eStyle = PointerStyle::Arrow;
1842     if ( mnSplitTest & SPLIT_HORZ )
1843         eStyle = PointerStyle::HSplit;
1844     else if ( mnSplitTest & SPLIT_VERT )
1845         eStyle = PointerStyle::VSplit;
1846 
1847     SetPointer( eStyle );
1848 }
1849 
StartSplit()1850 void SplitWindow::StartSplit()
1851 {
1852 }
1853 
Split()1854 void SplitWindow::Split()
1855 {
1856     maSplitHdl.Call( this );
1857 }
1858 
SplitResize()1859 void SplitWindow::SplitResize()
1860 {
1861 }
1862 
FadeIn()1863 void SplitWindow::FadeIn()
1864 {
1865 }
1866 
FadeOut()1867 void SplitWindow::FadeOut()
1868 {
1869 }
1870 
MouseButtonDown(const MouseEvent & rMEvt)1871 void SplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
1872 {
1873     if ( !rMEvt.IsLeft() || rMEvt.IsMod2() )
1874     {
1875         DockingWindow::MouseButtonDown( rMEvt );
1876         return;
1877     }
1878 
1879     Point           aMousePosPixel = rMEvt.GetPosPixel();
1880     tools::Rectangle       aTestRect;
1881 
1882     mbFadeNoButtonMode = false;
1883 
1884     ImplGetFadeOutRect( aTestRect );
1885     if ( aTestRect.IsInside( aMousePosPixel ) )
1886     {
1887         mbFadeOutDown = true;
1888         mbFadeOutPressed = true;
1889         Invalidate();
1890     }
1891     else
1892     {
1893         ImplGetFadeInRect( aTestRect, true );
1894         if ( aTestRect.IsInside( aMousePosPixel ) )
1895         {
1896             mbFadeInDown = true;
1897             mbFadeInPressed = true;
1898             Invalidate();
1899         }
1900         else if ( !aTestRect.IsEmpty() && !(mnWinStyle & WB_SIZEABLE) )
1901         {
1902             mbFadeNoButtonMode = true;
1903             FadeIn();
1904             return;
1905         }
1906     }
1907 
1908     if ( mbFadeInDown || mbFadeOutDown )
1909         StartTracking();
1910     else
1911         ImplStartSplit( rMEvt );
1912 }
1913 
MouseMove(const MouseEvent & rMEvt)1914 void SplitWindow::MouseMove( const MouseEvent& rMEvt )
1915 {
1916     if ( IsTracking() )
1917         return;
1918 
1919     Point           aPos = rMEvt.GetPosPixel();
1920     long            nTemp;
1921     ImplSplitSet*   pTempSplitSet;
1922     sal_uInt16          nTempSplitPos;
1923     sal_uInt16          nSplitTest = ImplTestSplit( this, aPos, nTemp, &pTempSplitSet, nTempSplitPos );
1924     PointerStyle    eStyle = PointerStyle::Arrow;
1925     tools::Rectangle       aFadeInRect;
1926     tools::Rectangle       aFadeOutRect;
1927 
1928     ImplGetFadeInRect( aFadeInRect );
1929     ImplGetFadeOutRect( aFadeOutRect );
1930     if ( !aFadeInRect.IsInside( aPos ) &&
1931          !aFadeOutRect.IsInside( aPos ) )
1932     {
1933         if ( nSplitTest && !(nSplitTest & SPLIT_NOSPLIT) )
1934         {
1935             if ( nSplitTest & SPLIT_HORZ )
1936                 eStyle = PointerStyle::HSplit;
1937             else if ( nSplitTest & SPLIT_VERT )
1938                 eStyle = PointerStyle::VSplit;
1939         }
1940     }
1941 
1942     SetPointer( eStyle );
1943 }
1944 
Tracking(const TrackingEvent & rTEvt)1945 void SplitWindow::Tracking( const TrackingEvent& rTEvt )
1946 {
1947     Point aMousePosPixel = rTEvt.GetMouseEvent().GetPosPixel();
1948 
1949     if ( mbFadeInDown )
1950     {
1951         if ( rTEvt.IsTrackingEnded() )
1952         {
1953             mbFadeInDown = false;
1954             if ( mbFadeInPressed )
1955             {
1956                 mbFadeInPressed = false;
1957                 Invalidate();
1958 
1959                 if ( !rTEvt.IsTrackingCanceled() )
1960                     FadeIn();
1961             }
1962         }
1963         else
1964         {
1965             tools::Rectangle aTestRect;
1966             ImplGetFadeInRect( aTestRect, true );
1967             bool bNewPressed = aTestRect.IsInside( aMousePosPixel );
1968             if ( bNewPressed != mbFadeInPressed )
1969             {
1970                 mbFadeInPressed = bNewPressed;
1971                 Invalidate();
1972             }
1973         }
1974     }
1975     else if ( mbFadeOutDown )
1976     {
1977         if ( rTEvt.IsTrackingEnded() )
1978         {
1979             mbFadeOutDown = false;
1980             if ( mbFadeOutPressed )
1981             {
1982                 mbFadeOutPressed = false;
1983                 Invalidate();
1984 
1985                 if ( !rTEvt.IsTrackingCanceled() )
1986                     FadeOut();
1987             }
1988         }
1989         else
1990         {
1991             tools::Rectangle aTestRect;
1992             ImplGetFadeOutRect( aTestRect );
1993             bool bNewPressed = aTestRect.IsInside( aMousePosPixel );
1994             if ( !bNewPressed )
1995             {
1996                 mbFadeOutPressed = bNewPressed;
1997                 Invalidate();
1998 
1999                 // We need a mouseevent with a position inside the button for the
2000                 // ImplStartSplit function!
2001                 MouseEvent aOrgMEvt = rTEvt.GetMouseEvent();
2002                 MouseEvent aNewMEvt( aTestRect.Center(), aOrgMEvt.GetClicks(),
2003                                      aOrgMEvt.GetMode(), aOrgMEvt.GetButtons(),
2004                                      aOrgMEvt.GetModifier() );
2005 
2006                 ImplStartSplit( aNewMEvt );
2007                 mbFadeOutDown = false;
2008             }
2009         }
2010     }
2011     else
2012     {
2013         ImplSplitMousePos( aMousePosPixel );
2014         bool bSplit = true;
2015         if ( mbDragFull )
2016         {
2017             if ( rTEvt.IsTrackingEnded() )
2018             {
2019                 if ( rTEvt.IsTrackingCanceled() )
2020                 {
2021                     std::vector< ImplSplitItem >& rItems = mpSplitSet->mvItems;
2022                     size_t          nItems = rItems.size();
2023                     for ( size_t i = 0; i < nItems; i++ )
2024                     {
2025                         rItems[i].mnSize     = mpLastSizes[i*2];
2026                         rItems[i].mnPixSize  = mpLastSizes[i*2+1];
2027                     }
2028                     ImplUpdate();
2029                     Split();
2030                 }
2031                 bSplit = false;
2032             }
2033         }
2034         else
2035         {
2036             if ( rTEvt.IsTrackingEnded() )
2037             {
2038                 HideTracking();
2039                 bSplit = !rTEvt.IsTrackingCanceled();
2040             }
2041             else
2042             {
2043                 ImplDrawSplitTracking(aMousePosPixel);
2044                 bSplit = false;
2045             }
2046         }
2047 
2048         if ( bSplit )
2049         {
2050             bool    bPropSmaller = (mnMouseModifier & KEY_SHIFT) != 0;
2051             bool    bPropGreater = (mnMouseModifier & KEY_MOD1) != 0;
2052             long    nDelta = mnMSplitPos-mnMStartPos;
2053 
2054             if ( (mnSplitTest & SPLIT_WINDOW) && mpMainSet->mvItems.empty() )
2055             {
2056                 if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
2057                     nDelta *= -1;
2058                 ImplSetWindowSize( nDelta );
2059             }
2060             else
2061             {
2062                 long nNewSize = mpSplitSet->mvItems[mnSplitPos].mnPixSize;
2063                 if ( (mpSplitSet == mpMainSet.get()) && mbBottomRight )
2064                     nNewSize -= nDelta;
2065                 else
2066                     nNewSize += nDelta;
2067                 SplitItem( mpSplitSet->mvItems[mnSplitPos].mnId, nNewSize,
2068                            bPropSmaller, bPropGreater );
2069             }
2070 
2071             Split();
2072 
2073             if ( mbDragFull )
2074             {
2075                 Update();
2076                 mnMStartPos = mnMSplitPos;
2077             }
2078         }
2079 
2080         if ( rTEvt.IsTrackingEnded() )
2081         {
2082             delete [] mpLastSizes;
2083             mpLastSizes     = nullptr;
2084             mpSplitSet      = nullptr;
2085             mnMouseOff      = 0;
2086             mnMStartPos     = 0;
2087             mnMSplitPos     = 0;
2088             mnMouseModifier = 0;
2089             mnSplitTest     = 0;
2090             mnSplitPos      = 0;
2091         }
2092     }
2093 }
2094 
PreNotify(NotifyEvent & rNEvt)2095 bool SplitWindow::PreNotify( NotifyEvent& rNEvt )
2096 {
2097     const MouseEvent* pMouseEvt = nullptr;
2098 
2099     if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
2100     {
2101         if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
2102         {
2103             // trigger redraw if mouse over state has changed
2104             tools::Rectangle aFadeInRect;
2105             tools::Rectangle aFadeOutRect;
2106             ImplGetFadeInRect( aFadeInRect );
2107             ImplGetFadeOutRect( aFadeOutRect );
2108 
2109             if ( aFadeInRect.IsInside( GetPointerPosPixel() ) != aFadeInRect.IsInside( GetLastPointerPosPixel() ) )
2110                 Invalidate( aFadeInRect );
2111             if ( aFadeOutRect.IsInside( GetPointerPosPixel() ) != aFadeOutRect.IsInside( GetLastPointerPosPixel() ) )
2112                 Invalidate( aFadeOutRect );
2113 
2114             if( pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
2115             {
2116                 Invalidate( aFadeInRect );
2117                 Invalidate( aFadeOutRect );
2118             }
2119         }
2120     }
2121     return Window::PreNotify( rNEvt );
2122 }
2123 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)2124 void SplitWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
2125 {
2126     if (mnWinStyle & WB_BORDER)
2127         ImplDrawBorder(rRenderContext);
2128 
2129     ImplDrawBorderLine(rRenderContext);
2130     ImplDrawFadeOut(rRenderContext);
2131     ImplDrawFadeIn(rRenderContext);
2132 
2133     // draw FrameSet-backgrounds
2134     ImplDrawBack(rRenderContext, mpMainSet.get());
2135 
2136     // draw splitter
2137     if (!(mnWinStyle & WB_NOSPLITDRAW))
2138     {
2139         ImplDrawSplit(rRenderContext, mpMainSet.get(), mbHorz, !mbBottomRight);
2140     }
2141 }
2142 
Resize()2143 void SplitWindow::Resize()
2144 {
2145     Size aSize = GetOutputSizePixel();
2146     mnDX = aSize.Width();
2147     mnDY = aSize.Height();
2148 
2149     ImplUpdate();
2150     Invalidate();
2151 }
2152 
RequestHelp(const HelpEvent & rHEvt)2153 void SplitWindow::RequestHelp( const HelpEvent& rHEvt )
2154 {
2155     // no keyboard help for splitwin
2156     if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) && !rHEvt.KeyboardActivated() )
2157     {
2158         Point       aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
2159         tools::Rectangle   aHelpRect;
2160         const char* pHelpResId = nullptr;
2161 
2162         ImplGetFadeInRect( aHelpRect, true );
2163         if ( aHelpRect.IsInside( aMousePosPixel ) )
2164             pHelpResId = SV_HELPTEXT_FADEIN;
2165         else
2166         {
2167             ImplGetFadeOutRect( aHelpRect );
2168             if ( aHelpRect.IsInside( aMousePosPixel ) )
2169                 pHelpResId = SV_HELPTEXT_FADEOUT;
2170         }
2171 
2172         // get rectangle
2173         if (pHelpResId)
2174         {
2175             Point aPt = OutputToScreenPixel( aHelpRect.TopLeft() );
2176             aHelpRect.SetLeft( aPt.X() );
2177             aHelpRect.SetTop( aPt.Y() );
2178             aPt = OutputToScreenPixel( aHelpRect.BottomRight() );
2179             aHelpRect.SetRight( aPt.X() );
2180             aHelpRect.SetBottom( aPt.Y() );
2181 
2182             // get and draw text
2183             OUString aStr = VclResId(pHelpResId);
2184             if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
2185                 Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aStr );
2186             else
2187                 Help::ShowQuickHelp( this, aHelpRect, aStr );
2188             return;
2189         }
2190     }
2191 
2192     DockingWindow::RequestHelp( rHEvt );
2193 }
2194 
StateChanged(StateChangedType nType)2195 void SplitWindow::StateChanged( StateChangedType nType )
2196 {
2197     switch ( nType )
2198     {
2199     case StateChangedType::InitShow:
2200         if ( IsUpdateMode() )
2201             ImplCalcLayout();
2202         break;
2203     case StateChangedType::UpdateMode:
2204         if ( IsUpdateMode() && IsReallyShown() )
2205             ImplCalcLayout();
2206         break;
2207     case StateChangedType::ControlBackground:
2208         ImplInitSettings();
2209         Invalidate();
2210         break;
2211     default:;
2212     }
2213 
2214     DockingWindow::StateChanged( nType );
2215 }
2216 
DataChanged(const DataChangedEvent & rDCEvt)2217 void SplitWindow::DataChanged( const DataChangedEvent& rDCEvt )
2218 {
2219     if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2220          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
2221     {
2222         ImplInitSettings();
2223         Invalidate();
2224     }
2225     else
2226         DockingWindow::DataChanged( rDCEvt );
2227 }
2228 
InsertItem(sal_uInt16 nId,vcl::Window * pWindow,long nSize,sal_uInt16 nPos,sal_uInt16 nIntoSetId,SplitWindowItemFlags nBits)2229 void SplitWindow::InsertItem( sal_uInt16 nId, vcl::Window* pWindow, long nSize,
2230                               sal_uInt16 nPos, sal_uInt16 nIntoSetId,
2231                               SplitWindowItemFlags nBits )
2232 {
2233 #ifdef DBG_UTIL
2234     sal_uInt16 nDbgDummy;
2235     SAL_WARN_IF( ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl", "SplitWindow::InsertItem() - Id already exists" );
2236 #endif
2237 
2238     // Size has to be at least 1.
2239     if ( nSize < 1 )
2240         nSize = 1;
2241 
2242     ImplSplitSet* pSet       = ImplFindSet( mpMainSet.get(), nIntoSetId );
2243 #ifdef DBG_UTIL
2244     SAL_WARN_IF( !pSet, "vcl", "SplitWindow::InsertItem() - Set not exists" );
2245 #endif
2246     if(!pSet)
2247     {
2248         return;
2249     }
2250 
2251     // Don't insert further than the end
2252     if ( nPos > pSet->mvItems.size() )
2253         nPos = pSet->mvItems.size();
2254 
2255     // Insert in set
2256     pSet->mvItems.emplace( pSet->mvItems.begin() + nPos );
2257 
2258     // init new item
2259     ImplSplitItem & aItem = pSet->mvItems[nPos];
2260     aItem.mnSize   = nSize;
2261     aItem.mnPixSize = 0;
2262     aItem.mnId     = nId;
2263     aItem.mnBits   = nBits;
2264     aItem.mnMinSize=-1;
2265     aItem.mnMaxSize=-1;
2266 
2267     if ( pWindow )
2268     {
2269         // New VclPtr reference
2270         aItem.mpWindow         = pWindow;
2271         aItem.mpOrgParent      = pWindow->GetParent();
2272 
2273         // Attach window to SplitWindow.
2274         pWindow->Hide();
2275         pWindow->SetParent( this );
2276     }
2277     else
2278     {
2279         ImplSplitSet * pNewSet  = new ImplSplitSet();
2280         pNewSet->mnId           = nId;
2281         pNewSet->mnSplitSize    = pSet->mnSplitSize;
2282 
2283         aItem.mpSet.reset(pNewSet);
2284     }
2285 
2286     pSet->mbCalcPix = true;
2287 
2288     ImplUpdate();
2289 }
2290 
InsertItem(sal_uInt16 nId,long nSize,sal_uInt16 nPos,sal_uInt16 nIntoSetId,SplitWindowItemFlags nBits)2291 void SplitWindow::InsertItem( sal_uInt16 nId, long nSize,
2292                               sal_uInt16 nPos, sal_uInt16 nIntoSetId,
2293                               SplitWindowItemFlags nBits )
2294 {
2295     InsertItem( nId, nullptr, nSize, nPos, nIntoSetId, nBits );
2296 }
2297 
RemoveItem(sal_uInt16 nId)2298 void SplitWindow::RemoveItem( sal_uInt16 nId )
2299 {
2300 #ifdef DBG_UTIL
2301     sal_uInt16 nDbgDummy;
2302     SAL_WARN_IF( !ImplFindItem( mpMainSet.get(), nId, nDbgDummy ), "vcl", "SplitWindow::RemoveItem() - Id not found" );
2303 #endif
2304 
2305     // search set
2306     sal_uInt16     nPos;
2307     ImplSplitSet*  pSet    = ImplFindItem( mpMainSet.get(), nId, nPos );
2308 
2309     if (!pSet)
2310         return;
2311 
2312     ImplSplitItem* pItem = &pSet->mvItems[nPos];
2313     VclPtr<vcl::Window> pWindow = pItem->mpWindow;
2314     VclPtr<vcl::Window> pOrgParent = pItem->mpOrgParent;
2315 
2316     // delete set if required
2317     if ( !pWindow )
2318         pItem->mpSet.reset();
2319 
2320     // remove item
2321     pSet->mbCalcPix = true;
2322     pSet->mvItems.erase( pSet->mvItems.begin() + nPos );
2323 
2324     ImplUpdate();
2325 
2326     // to have the least amounts of paints delete window only here
2327     if ( pWindow )
2328     {
2329         // restore window
2330         pWindow->Hide();
2331         pWindow->SetParent( pOrgParent );
2332     }
2333 
2334     // Clear and delete
2335     pWindow.clear();
2336     pOrgParent.clear();
2337 }
2338 
Clear()2339 void SplitWindow::Clear()
2340 {
2341     // create Main-Set again
2342     mpMainSet.reset(new ImplSplitSet());
2343     if ( mnWinStyle & WB_NOSPLITDRAW )
2344         mpMainSet->mnSplitSize -= 2;
2345     mpBaseSet = mpMainSet.get();
2346 
2347     // and invalidate again
2348     ImplUpdate();
2349 }
2350 
SplitItem(sal_uInt16 nId,long nNewSize,bool bPropSmall,bool bPropGreat)2351 void SplitWindow::SplitItem( sal_uInt16 nId, long nNewSize,
2352                              bool bPropSmall, bool bPropGreat )
2353 {
2354     sal_uInt16      nPos;
2355     ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
2356 
2357     if (!pSet)
2358         return;
2359 
2360     size_t           nItems = pSet->mvItems.size();
2361     std::vector< ImplSplitItem >&  rItems = pSet->mvItems;
2362 
2363     // When there is an explicit minimum or maximum size then move nNewSize
2364     // into that range (when it is not yet already in it.)
2365     nNewSize = ValidateSize(nNewSize, rItems[nPos]);
2366 
2367     if ( mbCalc )
2368     {
2369         rItems[nPos].mnSize = nNewSize;
2370         return;
2371     }
2372 
2373     long nDelta = nNewSize-rItems[nPos].mnPixSize;
2374     if ( !nDelta )
2375         return;
2376 
2377     // calculate area, which could be affected by splitting
2378     sal_uInt16 nMin = 0;
2379     sal_uInt16 nMax = nItems;
2380     for (size_t i = 0; i < nItems; ++i)
2381     {
2382         if ( rItems[i].mbFixed )
2383         {
2384             if ( i < nPos )
2385                 nMin = i+1;
2386             else
2387                 nMax = i;
2388         }
2389     }
2390 
2391     // treat TopSet different if the window is sizeable
2392     bool bSmall  = true;
2393     bool bGreat  = true;
2394     if ( (pSet == mpMainSet.get()) && (mnWinStyle & WB_SIZEABLE) )
2395     {
2396         if ( nPos < pSet->mvItems.size()-1 )
2397         {
2398             if ( !((bPropSmall && bPropGreat) ||
2399                    ((nDelta > 0) && bPropSmall) ||
2400                    ((nDelta < 0) && bPropGreat)) )
2401             {
2402                 if ( nDelta < 0 )
2403                     bGreat = false;
2404                 else
2405                     bSmall = false;
2406             }
2407         }
2408         else
2409         {
2410             if ( nDelta < 0 )
2411                 bGreat = false;
2412             else
2413                 bSmall = false;
2414         }
2415     }
2416     else if ( nPos >= nMax )
2417     {
2418         bSmall = false;
2419         bGreat = false;
2420     }
2421     else if ( nPos && (nPos >= pSet->mvItems.size()-1) )
2422     {
2423         nPos--;
2424         nDelta *= -1;
2425         bool bTemp = bPropSmall;
2426         bPropSmall = bPropGreat;
2427         bPropGreat = bTemp;
2428     }
2429 
2430     sal_uInt16          n;
2431     // now splitt the windows
2432     if ( nDelta < 0 )
2433     {
2434         if ( bGreat )
2435         {
2436             if ( bPropGreat )
2437             {
2438                 long nTempDelta = nDelta;
2439                 do
2440                 {
2441                     n = nPos+1;
2442                     do
2443                     {
2444                         if ( nTempDelta )
2445                         {
2446                             rItems[n].mnPixSize++;
2447                             nTempDelta++;
2448                         }
2449                         n++;
2450                     }
2451                     while ( n < nMax );
2452                 }
2453                 while ( nTempDelta );
2454             }
2455             else
2456                 rItems[nPos+1].mnPixSize -= nDelta;
2457         }
2458 
2459         if ( bSmall )
2460         {
2461             if ( bPropSmall )
2462             {
2463                 do
2464                 {
2465                     n = nPos+1;
2466                     do
2467                     {
2468                         if ( nDelta && rItems[n-1].mnPixSize )
2469                         {
2470                             rItems[n-1].mnPixSize--;
2471                             nDelta++;
2472                         }
2473 
2474                         n--;
2475                     }
2476                     while ( n > nMin );
2477                 }
2478                 while ( nDelta );
2479             }
2480             else
2481             {
2482                 n = nPos+1;
2483                 do
2484                 {
2485                     if ( rItems[n-1].mnPixSize+nDelta < 0 )
2486                     {
2487                         nDelta += rItems[n-1].mnPixSize;
2488                         rItems[n-1].mnPixSize = 0;
2489                     }
2490                     else
2491                     {
2492                         rItems[n-1].mnPixSize += nDelta;
2493                         break;
2494                     }
2495                     n--;
2496                 }
2497                 while ( n > nMin );
2498             }
2499         }
2500     }
2501     else
2502     {
2503         if ( bGreat )
2504         {
2505             if ( bPropGreat )
2506             {
2507                 long nTempDelta = nDelta;
2508                 do
2509                 {
2510                     n = nPos+1;
2511                     do
2512                     {
2513                         if ( nTempDelta )
2514                         {
2515                             rItems[n-1].mnPixSize++;
2516                             nTempDelta--;
2517                         }
2518                         n--;
2519                     }
2520                     while ( n > nMin );
2521                 }
2522                 while ( nTempDelta );
2523             }
2524             else
2525                 rItems[nPos].mnPixSize += nDelta;
2526         }
2527 
2528         if ( bSmall )
2529         {
2530             if ( bPropSmall )
2531             {
2532                 do
2533                 {
2534                     n = nPos+1;
2535                     do
2536                     {
2537                         if ( nDelta && rItems[n].mnPixSize )
2538                         {
2539                             rItems[n].mnPixSize--;
2540                             nDelta--;
2541                         }
2542 
2543                         n++;
2544                     }
2545                     while ( n < nMax );
2546                 }
2547                 while ( nDelta );
2548             }
2549             else
2550             {
2551                 n = nPos+1;
2552                 do
2553                 {
2554                     if ( rItems[n].mnPixSize-nDelta < 0 )
2555                     {
2556                         nDelta -= rItems[n].mnPixSize;
2557                         rItems[n].mnPixSize = 0;
2558                     }
2559                     else
2560                     {
2561                         rItems[n].mnPixSize -= nDelta;
2562                         break;
2563                     }
2564                     n++;
2565                 }
2566                 while ( n < nMax );
2567             }
2568         }
2569     }
2570 
2571     // update original sizes
2572     ImplCalcLogSize( rItems, nItems );
2573 
2574     ImplUpdate();
2575 }
2576 
SetItemSize(sal_uInt16 nId,long nNewSize)2577 void SplitWindow::SetItemSize( sal_uInt16 nId, long nNewSize )
2578 {
2579     sal_uInt16          nPos;
2580     ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
2581     ImplSplitItem*  pItem;
2582 
2583     if ( !pSet )
2584         return;
2585 
2586     // check if size is changed
2587     pItem = &pSet->mvItems[nPos];
2588     if ( pItem->mnSize != nNewSize )
2589     {
2590         // set new size and re-calculate
2591         pItem->mnSize = nNewSize;
2592         pSet->mbCalcPix = true;
2593         ImplUpdate();
2594     }
2595 }
2596 
GetItemSize(sal_uInt16 nId) const2597 long SplitWindow::GetItemSize( sal_uInt16 nId ) const
2598 {
2599     sal_uInt16          nPos;
2600     ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
2601 
2602     if ( pSet )
2603         return pSet->mvItems[nPos].mnSize;
2604     else
2605         return 0;
2606 }
2607 
GetItemSize(sal_uInt16 nId,SplitWindowItemFlags nBits) const2608 long SplitWindow::GetItemSize( sal_uInt16 nId, SplitWindowItemFlags nBits ) const
2609 {
2610     sal_uInt16          nPos;
2611     ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
2612 
2613     if ( pSet )
2614     {
2615         if ( nBits == pSet->mvItems[nPos].mnBits )
2616             return pSet->mvItems[nPos].mnSize;
2617         else
2618         {
2619             const_cast<SplitWindow*>(this)->ImplCalcLayout();
2620 
2621             long                nRelSize = 0;
2622             long                nPerSize = 0;
2623             size_t              nItems;
2624             SplitWindowItemFlags nTempBits;
2625             nItems = pSet->mvItems.size();
2626             std::vector< ImplSplitItem >& rItems = pSet->mvItems;
2627             for ( size_t i = 0; i < nItems; i++ )
2628             {
2629                 if ( i == nPos )
2630                     nTempBits = nBits;
2631                 else
2632                     nTempBits = rItems[i].mnBits;
2633                 if ( nTempBits & SplitWindowItemFlags::RelativeSize )
2634                     nRelSize += rItems[i].mnPixSize;
2635                 else if ( nTempBits & SplitWindowItemFlags::PercentSize )
2636                     nPerSize += rItems[i].mnPixSize;
2637             }
2638             nPerSize += nRelSize;
2639             if ( nBits & SplitWindowItemFlags::RelativeSize )
2640             {
2641                 if ( nRelSize )
2642                     return (rItems[nPos].mnPixSize+(nRelSize/2))/nRelSize;
2643                 else
2644                     return 1;
2645             }
2646             else if ( nBits & SplitWindowItemFlags::PercentSize )
2647             {
2648                 if ( nPerSize )
2649                     return (rItems[nPos].mnPixSize*100)/nPerSize;
2650                 else
2651                     return 1;
2652             }
2653             else
2654                 return rItems[nPos].mnPixSize;
2655         }
2656     }
2657     else
2658         return 0;
2659 }
2660 
SetItemSizeRange(sal_uInt16 nId,const Range & rRange)2661 void SplitWindow::SetItemSizeRange (sal_uInt16 nId, const Range& rRange)
2662 {
2663     sal_uInt16 nPos;
2664     ImplSplitSet* pSet = ImplFindItem(mpBaseSet, nId, nPos);
2665 
2666     if (pSet != nullptr)
2667     {
2668         pSet->mvItems[nPos].mnMinSize = rRange.Min();
2669         pSet->mvItems[nPos].mnMaxSize = rRange.Max();
2670     }
2671 }
2672 
GetSet(sal_uInt16 nId) const2673 sal_uInt16 SplitWindow::GetSet( sal_uInt16 nId ) const
2674 {
2675     sal_uInt16          nPos;
2676     ImplSplitSet*   pSet = ImplFindItem( mpBaseSet, nId, nPos );
2677 
2678     if ( pSet )
2679         return pSet->mnId;
2680     else
2681         return 0;
2682 }
2683 
IsItemValid(sal_uInt16 nId) const2684 bool SplitWindow::IsItemValid( sal_uInt16 nId ) const
2685 {
2686     sal_uInt16          nPos;
2687     ImplSplitSet* pSet = mpBaseSet ? ImplFindItem(mpBaseSet, nId, nPos) : nullptr;
2688 
2689     return pSet != nullptr;
2690 }
2691 
GetItemId(vcl::Window * pWindow) const2692 sal_uInt16 SplitWindow::GetItemId( vcl::Window* pWindow ) const
2693 {
2694     return ImplFindItem( mpBaseSet, pWindow );
2695 }
2696 
GetItemId(const Point & rPos) const2697 sal_uInt16 SplitWindow::GetItemId( const Point& rPos ) const
2698 {
2699     return ImplFindItem( mpBaseSet, rPos, mbHorz, !mbBottomRight );
2700 }
2701 
GetItemPos(sal_uInt16 nId,sal_uInt16 nSetId) const2702 sal_uInt16 SplitWindow::GetItemPos( sal_uInt16 nId, sal_uInt16 nSetId ) const
2703 {
2704     ImplSplitSet*   pSet = ImplFindSet( mpBaseSet, nSetId );
2705     sal_uInt16          nPos = SPLITWINDOW_ITEM_NOTFOUND;
2706 
2707     if ( pSet )
2708     {
2709         for ( size_t i = 0; i < pSet->mvItems.size(); i++ )
2710         {
2711             if ( pSet->mvItems[i].mnId == nId )
2712             {
2713                 nPos = i;
2714                 break;
2715             }
2716         }
2717     }
2718 
2719     return nPos;
2720 }
2721 
GetItemId(sal_uInt16 nPos) const2722 sal_uInt16 SplitWindow::GetItemId( sal_uInt16 nPos ) const
2723 {
2724     ImplSplitSet* pSet = ImplFindSet( mpBaseSet, 0/*nSetId*/ );
2725     if ( pSet && (nPos < pSet->mvItems.size()) )
2726         return pSet->mvItems[nPos].mnId;
2727     else
2728         return 0;
2729 }
2730 
GetItemCount(sal_uInt16 nSetId) const2731 sal_uInt16 SplitWindow::GetItemCount( sal_uInt16 nSetId ) const
2732 {
2733     ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId );
2734     if ( pSet )
2735         return pSet->mvItems.size();
2736     else
2737         return 0;
2738 }
2739 
ImplNewAlign()2740 void SplitWindow::ImplNewAlign()
2741 {
2742     switch ( meAlign )
2743     {
2744     case WindowAlign::Top:
2745         mbHorz        = true;
2746         mbBottomRight = false;
2747         break;
2748     case WindowAlign::Bottom:
2749         mbHorz        = true;
2750         mbBottomRight = true;
2751         break;
2752     case WindowAlign::Left:
2753         mbHorz        = false;
2754         mbBottomRight = false;
2755         break;
2756     case WindowAlign::Right:
2757         mbHorz        = false;
2758         mbBottomRight = true;
2759         break;
2760     }
2761 
2762     if ( mnWinStyle & WB_BORDER )
2763     {
2764         ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder,
2765                         mnRightBorder, mnBottomBorder );
2766     }
2767 
2768     if ( IsReallyVisible() && IsUpdateMode() )
2769         Invalidate();
2770     ImplUpdate();
2771 }
2772 
SetAlign(WindowAlign eNewAlign)2773 void SplitWindow::SetAlign( WindowAlign eNewAlign )
2774 {
2775     if ( meAlign != eNewAlign )
2776     {
2777         meAlign = eNewAlign;
2778         ImplNewAlign();
2779     }
2780 }
2781 
ShowFadeInHideButton()2782 void SplitWindow::ShowFadeInHideButton()
2783 {
2784     mbFadeIn = true;
2785     ImplUpdate();
2786 }
2787 
ShowFadeOutButton()2788 void SplitWindow::ShowFadeOutButton()
2789 {
2790     mbFadeOut = true;
2791     ImplUpdate();
2792 }
2793 
GetFadeInSize() const2794 long SplitWindow::GetFadeInSize() const
2795 {
2796     long n = 0;
2797 
2798     if ( mbHorz )
2799         n = mnTopBorder+mnBottomBorder;
2800     else
2801         n = mnLeftBorder+mnRightBorder;
2802 
2803     return n+SPLITWIN_SPLITSIZE+SPLITWIN_SPLITSIZEEX-2;
2804 }
2805 
2806 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2807