xref: /aoo41x/main/sfx2/source/sidebar/Deck.cxx (revision b9e67834)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #include "precompiled_sfx2.hxx"
23 
24 #include "Deck.hxx"
25 #include "DeckDescriptor.hxx"
26 #include "DrawHelper.hxx"
27 #include "DeckTitleBar.hxx"
28 #include "Paint.hxx"
29 #include "Panel.hxx"
30 #include "sfx2/sidebar/Theme.hxx"
31 
32 #include <tools/SvBorder.hxx>
33 
34 
35 namespace sfx2 { namespace sidebar {
36 
37 
38 namespace {
39     static const sal_Int32 MinimalPanelHeight (25);
40 }
41 
42 
43 
44 Deck::Deck (
45     const DeckDescriptor& rDeckDescriptor,
46     Window* pParentWindow)
47     : Window(pParentWindow),
48       msId(rDeckDescriptor.msId),
49       mpTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, this)),
50       maIcon(),
51       msIconURL(rDeckDescriptor.msIconURL),
52       msHighContrastIconURL(rDeckDescriptor.msHighContrastIconURL),
53       maPanels(),
54       maSeparators(),
55       mpFiller(NULL)
56 {
57     SetBackground(Wallpaper());
58 }
59 
60 
61 
62 
63 Deck::~Deck (void)
64 {
65     Dispose();
66 }
67 
68 
69 
70 
71 void Deck::Dispose (void)
72 {
73     ::std::vector<Panel*> aPanels;
74     aPanels.swap(maPanels);
75     for (::std::vector<Panel*>::const_iterator
76              iPanel(aPanels.begin()),
77              iEnd(aPanels.end());
78          iPanel!=iEnd;
79          ++iPanel)
80     {
81         (*iPanel)->Dispose();
82     }
83 }
84 
85 
86 
87 
88 const ::rtl::OUString& Deck::GetId (void) const
89 {
90     return msId;
91 }
92 
93 
94 
95 
96 TitleBar* Deck::GetTitleBar (void) const
97 {
98     return mpTitleBar;
99 }
100 
101 
102 
103 
104 Rectangle Deck::GetContentArea (void) const
105 {
106     const Size aWindowSize (GetSizePixel());
107     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
108 
109     return Rectangle(
110         Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize,
111         Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize,
112         aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
113         aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
114 }
115 
116 
117 
118 
119 ::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const
120 {
121     if (bIsHighContrastModeActive)
122         return msHighContrastIconURL;
123     else
124         return msIconURL;
125 }
126 
127 
128 
129 
130 void Deck::Paint (const Rectangle& rUpdateArea)
131 {
132     const Size aWindowSize (GetSizePixel());
133     const SvBorder aPadding (
134             Theme::GetInteger(Theme::Int_DeckLeftPadding),
135             Theme::GetInteger(Theme::Int_DeckTopPadding),
136             Theme::GetInteger(Theme::Int_DeckRightPadding),
137             Theme::GetInteger(Theme::Int_DeckBottomPadding));
138 
139     // Paint deck background outside the border.
140     Rectangle aBox(
141         0,
142         0,
143         aWindowSize.Width() - 1,
144         aWindowSize.Height() - 1);
145     DrawHelper::DrawBorder(
146         *this,
147         aBox,
148         aPadding,
149         Theme::GetPaint(Theme::Paint_DeckBackground),
150         Theme::GetPaint(Theme::Paint_DeckBackground));
151 
152     // Paint the border.
153     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
154     aBox.Left() += aPadding.Left();
155     aBox.Top() += aPadding.Top();
156     aBox.Right() -= aPadding.Right();
157     aBox.Bottom() -= aPadding.Bottom();
158     const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder));
159     DrawHelper::DrawBorder(
160         *this,
161         aBox,
162         SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize),
163         rHorizontalBorderPaint,
164         Theme::GetPaint(Theme::Paint_VerticalBorder));
165 
166     // Paint the separators.
167     const int nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
168     const int nLeft = aBox.Left() + nBorderSize;
169     const int nRight = aBox.Right() - nBorderSize;
170     for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end()); iY!=iEnd; ++iY)
171     {
172         DrawHelper::DrawHorizontalLine(
173             *this,
174             nLeft,
175             nRight,
176             *iY,
177             nSeparatorHeight,
178             rHorizontalBorderPaint);
179     }
180 }
181 
182 
183 
184 
185 void Deck::DataChanged (const DataChangedEvent& rEvent)
186 {
187     (void)rEvent;
188     RequestLayout();
189 }
190 
191 
192 
193 
194 void Deck::SetPanels (const ::std::vector<Panel*>& rPanels)
195 {
196     maPanels.resize(rPanels.size());
197     ::std::copy(rPanels.begin(), rPanels.end(), maPanels.begin());
198 
199     RequestLayout();
200 }
201 
202 
203 
204 
205 void Deck::RequestLayout (void)
206 {
207     switch(maPanels.size())
208     {
209         case 0:
210             // This basically is an error but there is not much that
211             // we can do about it.
212             if (mpFiller == NULL)
213             {
214                 OSL_ASSERT(maPanels.size()>0);
215             }
216             ShowFiller(PlaceDeckTitle(GetTitleBar(), GetContentArea()));
217             break;
218 
219         case 1:
220             if (maPanels[0]->IsTitleBarOptional())
221             {
222                 // There is only one panel in the deck and its title
223                 // bar is optional => do not draw the title bar.
224                 LayoutSinglePanel();
225             }
226             else
227                 LayoutMultiplePanels();
228             break;
229 
230         default:
231             LayoutMultiplePanels();
232             break;
233     }
234 
235     Invalidate();
236 }
237 
238 
239 
240 
241 void Deck::LayoutSinglePanel (void)
242 {
243     Rectangle aBox (GetContentArea());
244     aBox = PlaceDeckTitle(GetTitleBar(), aBox);
245     Panel& rPanel (*maPanels.front());
246 
247     // Prepare the separators, horizontal lines above and below the
248     // panel titels.
249     const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
250     maSeparators.clear();
251 
252     if (rPanel.IsExpanded())
253     {
254         rPanel.Show();
255         rPanel.GetTitleBar()->Hide();
256 
257         // Add single separator between deck title (pane title is not
258         // visible) and panel content.
259         maSeparators.push_back(aBox.Top());
260         aBox.Top() += nDeckSeparatorHeight;
261 
262         rPanel.SetPosSizePixel(aBox.Left(), aBox.Top(), aBox.GetWidth(), aBox.GetHeight());
263         HideFiller();
264     }
265     else
266     {
267         rPanel.Hide();
268         ShowFiller(aBox);
269     }
270 }
271 
272 
273 
274 
275 void Deck::LayoutMultiplePanels (void)
276 {
277     Rectangle aBox (GetContentArea());
278     if (aBox.GetWidth()<=0 || aBox.GetHeight()<=0)
279         return;
280     aBox = PlaceDeckTitle(GetTitleBar(), aBox);
281     const sal_Int32 nWidth (aBox.GetWidth());
282     const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight));
283 
284     // Prepare the separators, horizontal lines above and below the
285     // panel titels.
286     const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
287     maSeparators.clear();
288 
289     // Determine the height that is available for panel content
290     // and count the different layouts.
291     const sal_Int32 nX = aBox.Left();
292     sal_Int32 nHeight = aBox.GetHeight();
293     sal_Int32 nFullCount (0);
294     sal_Int32 nVerticalStackCount (0);
295     for (::std::vector<Panel*>::const_iterator
296              iPanel(maPanels.begin()),
297              iEnd(maPanels.end());
298          iPanel!=iEnd;
299          ++iPanel)
300     {
301         const Panel& rPanel (**iPanel);
302 
303         nHeight -= nPanelTitleBarHeight;
304         nHeight -= 2*nDeckSeparatorHeight;
305 
306         if (rPanel.IsExpanded())
307         {
308             if (rPanel.GetVerticalStackElement().is())
309             {
310                 ++nVerticalStackCount;
311                 const sal_Int32 nRequestedHeight (rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth));
312                 nHeight -= nRequestedHeight;
313             }
314             else
315             {
316                 ++nFullCount;
317             }
318         }
319     }
320 
321     sal_Int32 nHeightPerPanel (nFullCount<=0 ? 0 : nHeight / nFullCount);
322     // The division might lead to rounding errors.  Enlarge the first
323     // panel to compensate for that.
324     sal_Int32 nHeightOfFirstPanel = nFullCount+nVerticalStackCount<=0
325         ? 0
326         : nHeightPerPanel + (nHeight - nHeightPerPanel*(nFullCount+nVerticalStackCount));
327     if (nHeightPerPanel < MinimalPanelHeight)
328     {
329         // Display a vertical scroll bar.
330         // Force height to the minimal panel height.
331         nHeightPerPanel = MinimalPanelHeight;
332         nHeightOfFirstPanel = nHeightPerPanel;
333     }
334 
335     // Assign heights and places.
336     sal_Int32 nY (aBox.Top());
337     for (::std::vector<Panel*>::const_iterator
338              iPanel(maPanels.begin()),
339              iEnd(maPanels.end());
340          iPanel!=iEnd;
341          ++iPanel)
342     {
343         Panel& rPanel (**iPanel);
344 
345         // Separator above the panel title bar.
346         maSeparators.push_back(nY);
347         nY += nDeckSeparatorHeight;
348 
349         // Place the title bar.
350         TitleBar* pTitleBar = rPanel.GetTitleBar();
351         pTitleBar->SetPosSizePixel(nX, nY, nWidth, nPanelTitleBarHeight);
352         pTitleBar->Show();
353         nY += nPanelTitleBarHeight;
354 
355         // Separator below the panel title bar.
356         maSeparators.push_back(nY);
357         nY += nDeckSeparatorHeight;
358 
359         if (rPanel.IsExpanded())
360         {
361             rPanel.Show();
362 
363             // Place the panel.
364             sal_Int32 nPanelHeight (0);
365             if (rPanel.GetVerticalStackElement().is())
366                 nPanelHeight = rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth);
367             else
368                 if (iPanel==maPanels.begin())
369                     nPanelHeight = nHeightOfFirstPanel;
370                 else
371                     nPanelHeight = nHeightPerPanel;
372 
373             rPanel.SetPosSizePixel(nX, nY, nWidth, nPanelHeight);
374             nY += nPanelHeight;
375         }
376         else
377             rPanel.Hide();
378     }
379 
380     if (nY < aBox.Bottom())
381         ShowFiller(Rectangle(aBox.Left(), nY, aBox.Right(), aBox.Bottom()));
382     else
383         HideFiller();
384 }
385 
386 
387 
388 
389 Rectangle Deck::PlaceDeckTitle (
390     TitleBar* pDeckTitleBar,
391     const Rectangle& rAvailableSpace)
392 {
393     if (pDeckTitleBar == NULL)
394     {
395         OSL_ASSERT(pDeckTitleBar!=NULL);
396         return rAvailableSpace;
397     }
398 
399     const sal_Int32 nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight));
400     pDeckTitleBar->SetPosSizePixel(
401         rAvailableSpace.Left(),
402         rAvailableSpace.Top(),
403         rAvailableSpace.GetWidth(),
404         nDeckTitleBarHeight);
405     pDeckTitleBar->Show();
406     return Rectangle(
407         rAvailableSpace.Left(),
408         rAvailableSpace.Top() + nDeckTitleBarHeight,
409         rAvailableSpace.Right(),
410         rAvailableSpace.Bottom());
411 }
412 
413 
414 
415 
416 void Deck::ShowFiller (const Rectangle& rBox)
417 {
418     if (mpFiller == NULL)
419     {
420         mpFiller = new Window(this);
421         mpFiller->SetBackground(Theme::GetPaint(Theme::Paint_DeckBackground).GetWallpaper());
422     }
423     mpFiller->SetPosSizePixel(rBox.TopLeft(), rBox.GetSize());
424     mpFiller->Show();
425 }
426 
427 
428 
429 
430 void Deck::HideFiller (void)
431 {
432     if (mpFiller != NULL)
433         mpFiller->Hide();
434 }
435 
436 
437 
438 } } // end of namespace sfx2::sidebar
439