xref: /trunk/main/sfx2/source/sidebar/Deck.cxx (revision 95a18594)
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 		if (*iPanel != NULL)
82 			(*iPanel)->Dispose();
83     }
84 }
85 
86 
87 
88 
89 const ::rtl::OUString& Deck::GetId (void) const
90 {
91     return msId;
92 }
93 
94 
95 
96 
97 TitleBar* Deck::GetTitleBar (void) const
98 {
99     return mpTitleBar;
100 }
101 
102 
103 
104 
105 Rectangle Deck::GetContentArea (void) const
106 {
107     const Size aWindowSize (GetSizePixel());
108     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
109 
110     return Rectangle(
111         Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize,
112         Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize,
113         aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
114         aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
115 }
116 
117 
118 
119 
120 ::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const
121 {
122     if (bIsHighContrastModeActive)
123         return msHighContrastIconURL;
124     else
125         return msIconURL;
126 }
127 
128 
129 
130 
131 void Deck::Paint (const Rectangle& rUpdateArea)
132 {
133     (void) rUpdateArea;
134 
135     const Size aWindowSize (GetSizePixel());
136     const SvBorder aPadding (
137             Theme::GetInteger(Theme::Int_DeckLeftPadding),
138             Theme::GetInteger(Theme::Int_DeckTopPadding),
139             Theme::GetInteger(Theme::Int_DeckRightPadding),
140             Theme::GetInteger(Theme::Int_DeckBottomPadding));
141 
142     // Paint deck background outside the border.
143     Rectangle aBox(
144         0,
145         0,
146         aWindowSize.Width() - 1,
147         aWindowSize.Height() - 1);
148     DrawHelper::DrawBorder(
149         *this,
150         aBox,
151         aPadding,
152         Theme::GetPaint(Theme::Paint_DeckBackground),
153         Theme::GetPaint(Theme::Paint_DeckBackground));
154 
155     // Paint the border.
156     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
157     aBox.Left() += aPadding.Left();
158     aBox.Top() += aPadding.Top();
159     aBox.Right() -= aPadding.Right();
160     aBox.Bottom() -= aPadding.Bottom();
161     const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder));
162     DrawHelper::DrawBorder(
163         *this,
164         aBox,
165         SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize),
166         rHorizontalBorderPaint,
167         Theme::GetPaint(Theme::Paint_VerticalBorder));
168 
169     // Paint the separators.
170     const int nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
171     const int nLeft = aBox.Left() + nBorderSize;
172     const int nRight = aBox.Right() - nBorderSize;
173     for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end()); iY!=iEnd; ++iY)
174     {
175         DrawHelper::DrawHorizontalLine(
176             *this,
177             nLeft,
178             nRight,
179             *iY,
180             nSeparatorHeight,
181             rHorizontalBorderPaint);
182     }
183 }
184 
185 
186 
187 
188 void Deck::DataChanged (const DataChangedEvent& rEvent)
189 {
190     (void)rEvent;
191     RequestLayout();
192 }
193 
194 
195 
196 
197 void Deck::SetPanels (const ::std::vector<Panel*>& rPanels)
198 {
199     maPanels.resize(rPanels.size());
200     ::std::copy(rPanels.begin(), rPanels.end(), maPanels.begin());
201 
202     RequestLayout();
203 }
204 
205 
206 
207 
208 void Deck::RequestLayout (void)
209 {
210     switch(maPanels.size())
211     {
212         case 0:
213             // This basically is an error but there is not much that
214             // we can do about it.
215             ShowFiller(PlaceDeckTitle(GetTitleBar(), GetContentArea()));
216             break;
217 
218         case 1:
219             if (maPanels[0]->IsTitleBarOptional())
220             {
221                 // There is only one panel in the deck and its title
222                 // bar is optional => do not draw the title bar.
223                 LayoutSinglePanel();
224             }
225             else
226                 LayoutMultiplePanels();
227             break;
228 
229         default:
230             LayoutMultiplePanels();
231             break;
232     }
233 
234     Invalidate();
235 }
236 
237 
238 
239 
240 void Deck::LayoutSinglePanel (void)
241 {
242     Rectangle aBox (GetContentArea());
243     aBox = PlaceDeckTitle(GetTitleBar(), aBox);
244     Panel& rPanel (*maPanels.front());
245 
246     // Prepare the separators, horizontal lines above and below the
247     // panel titels.
248     const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
249     maSeparators.clear();
250 
251     if (rPanel.IsExpanded())
252     {
253         rPanel.Show();
254         rPanel.GetTitleBar()->Hide();
255 
256         // Add single separator between deck title (pane title is not
257         // visible) and panel content.
258         maSeparators.push_back(aBox.Top());
259         aBox.Top() += nDeckSeparatorHeight;
260 
261         rPanel.SetPosSizePixel(aBox.Left(), aBox.Top(), aBox.GetWidth(), aBox.GetHeight());
262         HideFiller();
263     }
264     else
265     {
266         rPanel.Hide();
267         ShowFiller(aBox);
268     }
269 }
270 
271 
272 
273 
274 void Deck::LayoutMultiplePanels (void)
275 {
276     Rectangle aBox (GetContentArea());
277     if (aBox.GetWidth()<=0 || aBox.GetHeight()<=0)
278         return;
279     aBox = PlaceDeckTitle(GetTitleBar(), aBox);
280     const sal_Int32 nWidth (aBox.GetWidth());
281     const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight));
282 
283     // Prepare the separators, horizontal lines above and below the
284     // panel titels.
285     const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
286     maSeparators.clear();
287 
288     // Determine the height that is available for panel content
289     // and count the different layouts.
290     const sal_Int32 nX = aBox.Left();
291     sal_Int32 nHeight = aBox.GetHeight();
292     sal_Int32 nFullCount (0);
293     sal_Int32 nVerticalStackCount (0);
294     for (::std::vector<Panel*>::const_iterator
295              iPanel(maPanels.begin()),
296              iEnd(maPanels.end());
297          iPanel!=iEnd;
298          ++iPanel)
299     {
300 		if (*iPanel == NULL)
301 			continue;
302 
303 		const Panel& rPanel (**iPanel);
304 
305         nHeight -= nPanelTitleBarHeight;
306         nHeight -= 2*nDeckSeparatorHeight;
307 
308         if (rPanel.IsExpanded())
309         {
310             if (rPanel.GetVerticalStackElement().is())
311             {
312                 const sal_Int32 nRequestedHeight (rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth));
313                 if (nRequestedHeight >= 0)
314                 {
315                     ++nVerticalStackCount;
316                     nHeight -= nRequestedHeight;
317                 }
318                 else
319                 {
320                     // Treat -1 as a special value that the panel
321                     // wants as much space as possible.
322                     ++nFullCount;
323                 }
324             }
325             else
326             {
327                 ++nFullCount;
328             }
329         }
330     }
331 
332     // The remaining height is distributed between the full size panels.
333     sal_Int32 nHeightPerPanel (nFullCount<=0 ? 0 : nHeight / nFullCount);
334 
335     // The division might lead to rounding errors.  Enlarge the first
336     // panel to compensate for that.
337     sal_Int32 nHeightOfFirstPanel = nFullCount+nVerticalStackCount<=0
338         ? 0
339         : nHeightPerPanel + (nHeight - nHeightPerPanel*nFullCount);
340     if (nHeightPerPanel < MinimalPanelHeight)
341     {
342         // Display a vertical scroll bar.
343         // Force height to the minimal panel height.
344         nHeightPerPanel = MinimalPanelHeight;
345         nHeightOfFirstPanel = nHeightPerPanel;
346     }
347 
348     // Assign heights and places.
349     sal_Int32 nY (aBox.Top());
350     for (::std::vector<Panel*>::const_iterator
351              iPanel(maPanels.begin()),
352              iEnd(maPanels.end());
353          iPanel!=iEnd;
354          ++iPanel)
355     {
356 		if (*iPanel == NULL)
357 			continue;
358 
359         Panel& rPanel (**iPanel);
360 
361         // Separator above the panel title bar.
362         maSeparators.push_back(nY);
363         nY += nDeckSeparatorHeight;
364 
365         // Place the title bar.
366         TitleBar* pTitleBar = rPanel.GetTitleBar();
367         pTitleBar->SetPosSizePixel(nX, nY, nWidth, nPanelTitleBarHeight);
368         pTitleBar->Show();
369         nY += nPanelTitleBarHeight;
370 
371         // Separator below the panel title bar.
372         maSeparators.push_back(nY);
373         nY += nDeckSeparatorHeight;
374 
375         if (rPanel.IsExpanded())
376         {
377             rPanel.Show();
378 
379             // Place the panel.
380             sal_Int32 nPanelHeight (0);
381             if (rPanel.GetVerticalStackElement().is())
382                 nPanelHeight = rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth);
383             else
384                 if (iPanel==maPanels.begin())
385                     nPanelHeight = nHeightOfFirstPanel;
386                 else
387                     nPanelHeight = nHeightPerPanel;
388 
389             rPanel.SetPosSizePixel(nX, nY, nWidth, nPanelHeight);
390             nY += nPanelHeight;
391         }
392         else
393             rPanel.Hide();
394     }
395 
396     if (nY < aBox.Bottom())
397         ShowFiller(Rectangle(aBox.Left(), nY, aBox.Right(), aBox.Bottom()));
398     else
399         HideFiller();
400 }
401 
402 
403 
404 
405 Rectangle Deck::PlaceDeckTitle (
406     TitleBar* pDeckTitleBar,
407     const Rectangle& rAvailableSpace)
408 {
409     if (pDeckTitleBar == NULL)
410     {
411         OSL_ASSERT(pDeckTitleBar!=NULL);
412         return rAvailableSpace;
413     }
414 
415     const sal_Int32 nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight));
416     pDeckTitleBar->SetPosSizePixel(
417         rAvailableSpace.Left(),
418         rAvailableSpace.Top(),
419         rAvailableSpace.GetWidth(),
420         nDeckTitleBarHeight);
421     pDeckTitleBar->Show();
422     return Rectangle(
423         rAvailableSpace.Left(),
424         rAvailableSpace.Top() + nDeckTitleBarHeight,
425         rAvailableSpace.Right(),
426         rAvailableSpace.Bottom());
427 }
428 
429 
430 
431 
432 void Deck::ShowFiller (const Rectangle& rBox)
433 {
434     if (mpFiller == NULL)
435     {
436         mpFiller = new Window(this);
437     }
438     mpFiller->SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground).GetWallpaper());
439     mpFiller->SetPosSizePixel(rBox.TopLeft(), rBox.GetSize());
440     mpFiller->Show();
441 }
442 
443 
444 
445 
446 void Deck::HideFiller (void)
447 {
448     if (mpFiller != NULL)
449         mpFiller->Hide();
450 }
451 
452 
453 
454 } } // end of namespace sfx2::sidebar
455