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 <vcl/layout.hxx>
21 #include <PriorityHBox.hxx>
22 #include <comphelper/lok.hxx>
23 
24 namespace
25 {
lcl_comparePriority(const vcl::IPrioritable * a,const vcl::IPrioritable * b)26 bool lcl_comparePriority(const vcl::IPrioritable* a, const vcl::IPrioritable* b)
27 {
28     return a->GetPriority() < b->GetPriority();
29 }
30 }
31 
PriorityHBox(vcl::Window * pParent)32 PriorityHBox::PriorityHBox(vcl::Window* pParent)
33     : VclHBox(pParent)
34     , m_bInitialized(false)
35 {
36 }
37 
~PriorityHBox()38 PriorityHBox::~PriorityHBox() { disposeOnce(); }
39 
Initialize()40 void PriorityHBox::Initialize()
41 {
42     m_bInitialized = true;
43 
44     GetChildrenWithPriorities();
45     SetSizeFromParent();
46 }
47 
GetHiddenCount() const48 int PriorityHBox::GetHiddenCount() const
49 {
50     int nCount = 0;
51 
52     for (auto pWindow : m_aSortedChildren)
53         if (pWindow->IsHidden())
54             nCount++;
55 
56     return nCount;
57 }
58 
SetSizeFromParent()59 void PriorityHBox::SetSizeFromParent()
60 {
61     vcl::Window* pParent = GetParent();
62     if (pParent)
63     {
64         Size aParentSize = pParent->GetSizePixel();
65         SetSizePixel(Size(aParentSize.getWidth(), aParentSize.getHeight()));
66     }
67 }
68 
calculateRequisition() const69 Size PriorityHBox::calculateRequisition() const
70 {
71     if (!m_bInitialized)
72     {
73         return VclHBox::calculateRequisition();
74     }
75 
76     sal_uInt16 nVisibleChildren = 0;
77 
78     Size aSize;
79     for (vcl::Window* pChild = GetWindow(GetWindowType::FirstChild); pChild;
80          pChild = pChild->GetWindow(GetWindowType::Next))
81     {
82         if (!pChild->IsVisible())
83             continue;
84         ++nVisibleChildren;
85         Size aChildSize = getLayoutRequisition(*pChild);
86 
87         bool bAlwaysExpanded = true;
88 
89         vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
90         if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
91             bAlwaysExpanded = false;
92 
93         if (bAlwaysExpanded)
94         {
95             tools::Long nPrimaryDimension = getPrimaryDimension(aChildSize);
96             nPrimaryDimension += pChild->get_padding() * 2;
97             setPrimaryDimension(aChildSize, nPrimaryDimension);
98         }
99         else
100             setPrimaryDimension(aChildSize, 0);
101 
102         accumulateMaxes(aChildSize, aSize);
103     }
104 
105     return finalizeMaxes(aSize, nVisibleChildren);
106 }
107 
Resize()108 void PriorityHBox::Resize()
109 {
110     if (!m_bInitialized)
111         Initialize();
112 
113     if (!m_bInitialized || comphelper::LibreOfficeKit::isActive())
114     {
115         return VclHBox::Resize();
116     }
117 
118     tools::Long nWidth = GetSizePixel().Width();
119     tools::Long nCurrentWidth = VclHBox::calculateRequisition().getWidth();
120 
121     // Hide lower priority controls
122     for (vcl::IPrioritable* pPrioritable : m_aSortedChildren)
123     {
124         if (nCurrentWidth <= nWidth)
125             break;
126 
127         vcl::Window* pWindow = dynamic_cast<vcl::Window*>(pPrioritable);
128 
129         if (pWindow && pWindow->GetParent() == this)
130         {
131             nCurrentWidth -= pWindow->GetOutDev()->GetOutputWidthPixel() + get_spacing();
132             pWindow->Show();
133             pPrioritable->HideContent();
134             nCurrentWidth += pWindow->GetOutDev()->GetOutputWidthPixel() + get_spacing();
135         }
136     }
137 
138     auto pChildR = m_aSortedChildren.rbegin();
139     // Show higher priority controls if we already have enough space
140     while (pChildR != m_aSortedChildren.rend())
141     {
142         vcl::Window* pWindow = dynamic_cast<vcl::Window*>(*pChildR);
143         vcl::IPrioritable* pPrioritable = *pChildR;
144 
145         if (pWindow->GetParent() != this)
146         {
147             pChildR++;
148             continue;
149         }
150 
151         if (pWindow)
152         {
153             nCurrentWidth -= pWindow->GetOutDev()->GetOutputWidthPixel() + get_spacing();
154             pWindow->Show();
155             pPrioritable->ShowContent();
156             nCurrentWidth += getLayoutRequisition(*pWindow).Width() + get_spacing();
157 
158             if (nCurrentWidth > nWidth)
159             {
160                 pPrioritable->HideContent();
161                 break;
162             }
163         }
164 
165         pChildR++;
166     }
167 
168     VclHBox::Resize();
169 }
170 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)171 void PriorityHBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
172 {
173     if (!m_bInitialized)
174         Initialize();
175 
176     VclHBox::Paint(rRenderContext, rRect);
177 }
178 
GetChildrenWithPriorities()179 void PriorityHBox::GetChildrenWithPriorities()
180 {
181     for (sal_uInt16 i = 0; i < GetChildCount(); ++i)
182     {
183         vcl::Window* pChild = GetChild(i);
184 
185         // Add only containers which have explicitly assigned priority.
186         vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
187         if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
188             m_aSortedChildren.push_back(pPrioritable);
189     }
190 
191     if (m_aSortedChildren.empty())
192         m_bInitialized = false;
193 
194     std::sort(m_aSortedChildren.begin(), m_aSortedChildren.end(), lcl_comparePriority);
195 }
196 
197 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
198