xref: /trunk/main/sfx2/source/sidebar/Deck.cxx (revision a1fa6b52)
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 "DeckLayouter.hxx"
27 #include "DrawHelper.hxx"
28 #include "DeckTitleBar.hxx"
29 #include "Paint.hxx"
30 #include "Panel.hxx"
31 #include "ToolBoxBackground.hxx"
32 #include "sfx2/sidebar/Tools.hxx"
33 #include "sfx2/sidebar/Theme.hxx"
34 
35 #include <vcl/dockwin.hxx>
36 #include <vcl/scrbar.hxx>
37 #include <tools/svborder.hxx>
38 
39 #include <boost/bind.hpp>
40 
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 
44 
45 namespace sfx2 { namespace sidebar {
46 
47 
48 namespace {
49     static const sal_Int32 MinimalPanelHeight (25);
50 }
51 
52 
53 Deck::Deck (
54     const DeckDescriptor& rDeckDescriptor,
55     Window* pParentWindow,
56     const ::boost::function<void(void)>& rCloserAction)
57     : Window(pParentWindow, 0),
58       msId(rDeckDescriptor.msId),
59       maIcon(),
60       msIconURL(rDeckDescriptor.msIconURL),
61       msHighContrastIconURL(rDeckDescriptor.msHighContrastIconURL),
62       maPanels(),
63       mpTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, this, rCloserAction)),
64       mpScrollClipWindow(new Window(this)),
65       mpScrollContainer(new ScrollContainerWindow(mpScrollClipWindow.get())),
66       mpFiller(new Window(this)),
67       mpVerticalScrollBar(new ScrollBar(this))
68 {
69     SetBackground(Wallpaper());
70 
71     mpScrollClipWindow->SetBackground(Wallpaper());
72     mpScrollClipWindow->Show();
73 
74     mpScrollContainer->SetStyle(mpScrollContainer->GetStyle() | WB_DIALOGCONTROL);
75     mpScrollContainer->SetBackground(Wallpaper());
76     mpScrollContainer->Show();
77 
78     mpVerticalScrollBar->SetScrollHdl(LINK(this, Deck, HandleVerticalScrollBarChange));
79 
80 #ifdef DEBUG
81     SetText(A2S("Deck"));
82     mpScrollClipWindow->SetText(A2S("ScrollClipWindow"));
83     mpFiller->SetText(A2S("Filler"));
84     mpVerticalScrollBar->SetText(A2S("VerticalScrollBar"));
85 #endif
86 }
87 
88 
89 
90 
91 Deck::~Deck (void)
92 {
93     Dispose();
94 
95     // We have to explicitly trigger the destruction of panels.
96     // Otherwise that is done by one of our base class destructors
97     // without updating maPanels.
98     maPanels.clear();
99 }
100 
101 
102 
103 
104 void Deck::Dispose (void)
105 {
106     SharedPanelContainer aPanels;
107     aPanels.swap(maPanels);
108     for (SharedPanelContainer::iterator
109              iPanel(aPanels.begin()),
110              iEnd(aPanels.end());
111          iPanel!=iEnd;
112          ++iPanel)
113     {
114 		if (*iPanel)
115         {
116 			(*iPanel)->Dispose();
117             OSL_ASSERT(iPanel->unique());
118             iPanel->reset();
119         }
120     }
121 
122     mpTitleBar.reset();
123     mpFiller.reset();
124     mpVerticalScrollBar.reset();
125 }
126 
127 
128 
129 
130 const ::rtl::OUString& Deck::GetId (void) const
131 {
132     return msId;
133 }
134 
135 
136 
137 
138 DeckTitleBar* Deck::GetTitleBar (void) const
139 {
140     return mpTitleBar.get();
141 }
142 
143 
144 
145 
146 Rectangle Deck::GetContentArea (void) const
147 {
148     const Size aWindowSize (GetSizePixel());
149     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
150 
151     return Rectangle(
152         Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize,
153         Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize,
154         aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
155         aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
156 }
157 
158 
159 
160 
161 ::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const
162 {
163     if (bIsHighContrastModeActive)
164         return msHighContrastIconURL;
165     else
166         return msIconURL;
167 }
168 
169 
170 
171 
172 void Deck::Paint (const Rectangle& rUpdateArea)
173 {
174     (void) rUpdateArea;
175 
176     const Size aWindowSize (GetSizePixel());
177     const SvBorder aPadding (
178             Theme::GetInteger(Theme::Int_DeckLeftPadding),
179             Theme::GetInteger(Theme::Int_DeckTopPadding),
180             Theme::GetInteger(Theme::Int_DeckRightPadding),
181             Theme::GetInteger(Theme::Int_DeckBottomPadding));
182 
183     // Paint deck background outside the border.
184     Rectangle aBox(
185         0,
186         0,
187         aWindowSize.Width() - 1,
188         aWindowSize.Height() - 1);
189     DrawHelper::DrawBorder(
190         *this,
191         aBox,
192         aPadding,
193         Theme::GetPaint(Theme::Paint_DeckBackground),
194         Theme::GetPaint(Theme::Paint_DeckBackground));
195 
196     // Paint the border.
197     const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
198     aBox.Left() += aPadding.Left();
199     aBox.Top() += aPadding.Top();
200     aBox.Right() -= aPadding.Right();
201     aBox.Bottom() -= aPadding.Bottom();
202     const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder));
203     DrawHelper::DrawBorder(
204         *this,
205         aBox,
206         SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize),
207         rHorizontalBorderPaint,
208         Theme::GetPaint(Theme::Paint_VerticalBorder));
209 }
210 
211 
212 
213 
214 void Deck::DataChanged (const DataChangedEvent& rEvent)
215 {
216     (void)rEvent;
217     RequestLayout();
218 }
219 
220 
221 
222 
223 long Deck::Notify (NotifyEvent& rEvent)
224 {
225     if (rEvent.GetType() == EVENT_COMMAND)
226     {
227         CommandEvent* pCommandEvent = reinterpret_cast<CommandEvent*>(rEvent.GetData());
228         if (pCommandEvent != NULL)
229             switch (pCommandEvent->GetCommand())
230             {
231                 case COMMAND_WHEEL:
232                     return ProcessWheelEvent(pCommandEvent, rEvent)
233                         ? sal_True
234                         : sal_False;
235 
236                 default:
237                     break;
238             }
239     }
240 
241     return Window::Notify(rEvent);
242 }
243 
244 
245 
246 
247 bool Deck::ProcessWheelEvent (
248     CommandEvent* pCommandEvent,
249     NotifyEvent& rEvent)
250 {
251     if ( ! mpVerticalScrollBar)
252         return false;
253     if ( ! mpVerticalScrollBar->IsVisible())
254         return false;
255 
256     // Ignore all wheel commands from outside the vertical scroll bar.
257     // Otherwise after a scroll we might land on a spin field and
258     // subsequent wheel events would change the value of that control.
259     if (rEvent.GetWindow() != mpVerticalScrollBar.get())
260         return true;
261 
262     // Get the wheel data and check that it describes a valid vertical
263     // scroll.
264     const CommandWheelData* pData = pCommandEvent->GetWheelData();
265     if (pData==NULL
266         || pData->GetModifier()
267         || pData->GetMode() != COMMAND_WHEEL_SCROLL
268         || pData->IsHorz())
269         return false;
270 
271     // Execute the actual scroll action.
272     long nDelta = pData->GetDelta();
273     mpVerticalScrollBar->DoScroll(
274         mpVerticalScrollBar->GetThumbPos() - nDelta);
275     return true;
276 }
277 
278 
279 
280 
281 void Deck::SetPanels (const SharedPanelContainer& rPanels)
282 {
283     maPanels = rPanels;
284 
285     RequestLayout();
286 }
287 
288 
289 
290 
291 const SharedPanelContainer& Deck::GetPanels (void) const
292 {
293     return maPanels;
294 }
295 
296 
297 
298 
299 void Deck::RequestLayout (void)
300 {
301     //    PrintWindowTree();
302 
303     DeckLayouter::LayoutDeck(
304         GetContentArea(),
305         maPanels,
306         *GetTitleBar(),
307         *mpScrollClipWindow,
308         *mpScrollContainer,
309         *mpFiller,
310         *mpVerticalScrollBar);
311 
312     Invalidate();
313 }
314 
315 
316 
317 
318 ::Window* Deck::GetPanelParentWindow (void)
319 {
320     return mpScrollContainer.get();
321 }
322 
323 
324 
325 
326 void Deck::ShowPanel (const Panel& rPanel)
327 {
328     if (mpVerticalScrollBar && mpVerticalScrollBar->IsVisible())
329     {
330         // Get vertical extent of the panel.
331         sal_Int32 nPanelTop (rPanel.GetPosPixel().Y());
332         const sal_Int32 nPanelBottom (nPanelTop + rPanel.GetSizePixel().Height() - 1);
333         // Add the title bar into the extent.
334         if (rPanel.GetTitleBar() != NULL && rPanel.GetTitleBar()->IsVisible())
335             nPanelTop = rPanel.GetTitleBar()->GetPosPixel().Y();
336 
337         // Determine what the new thumb position should be like.
338         // When the whole panel does not fit then make its top visible
339         // and it off at the bottom.
340         sal_Int32 nNewThumbPos (mpVerticalScrollBar->GetThumbPos());
341         if (nPanelBottom >= nNewThumbPos+mpVerticalScrollBar->GetVisibleSize())
342             nNewThumbPos = nPanelBottom - mpVerticalScrollBar->GetVisibleSize();
343         if (nPanelTop < nNewThumbPos)
344             nNewThumbPos = nPanelTop;
345 
346         mpVerticalScrollBar->SetThumbPos(nNewThumbPos);
347         mpScrollContainer->SetPosPixel(
348             Point(
349                 mpScrollContainer->GetPosPixel().X(),
350                 -nNewThumbPos));
351 
352     }
353 }
354 
355 
356 
357 
358 const char* GetWindowClassification (const Window* pWindow)
359 {
360     const String& rsName (pWindow->GetText());
361     if (rsName.Len() > 0)
362     {
363         return ::rtl::OUStringToOString(rsName, RTL_TEXTENCODING_ASCII_US).getStr();
364     }
365     else
366     {
367         static char msWindow[] = "window";
368         return msWindow;
369     }
370 }
371 
372 
373 void Deck::PrintWindowSubTree (Window* pRoot, int nIndentation)
374 {
375     static const char* sIndentation = "                                                                  ";
376     const Point aLocation (pRoot->GetPosPixel());
377     const Size aSize (pRoot->GetSizePixel());
378     const char* sClassification = GetWindowClassification(pRoot);
379     const char* sVisible = pRoot->IsVisible() ? "visible" : "hidden";
380     OSL_TRACE("%s%x %s %s +%d+%d x%dx%d",
381         sIndentation+strlen(sIndentation)-nIndentation*4,
382         pRoot,
383         sClassification,
384         sVisible,
385         aLocation.X(),aLocation.Y(),
386         aSize.Width(),aSize.Height());
387 
388     const sal_uInt16 nChildCount (pRoot->GetChildCount());
389     for (sal_uInt16 nIndex=0; nIndex<nChildCount; ++nIndex)
390         PrintWindowSubTree(pRoot->GetChild(nIndex), nIndentation+1);
391 }
392 
393 
394 
395 
396 void Deck::PrintWindowTree (void)
397 {
398     PrintWindowSubTree(this, 0);
399 }
400 
401 
402 
403 
404 void Deck::PrintWindowTree (const ::std::vector<Panel*>& rPanels)
405 {
406     (void)rPanels;
407 
408     PrintWindowTree();
409 }
410 
411 
412 
413 
414 IMPL_LINK(Deck, HandleVerticalScrollBarChange,void*, EMPTYARG)
415 {
416     const sal_Int32 nYOffset (-mpVerticalScrollBar->GetThumbPos());
417     mpScrollContainer->SetPosPixel(
418         Point(
419             mpScrollContainer->GetPosPixel().X(),
420             nYOffset));
421     return sal_True;
422 }
423 
424 
425 
426 
427 //----- Deck::ScrollContainerWindow -------------------------------------------
428 
429 Deck::ScrollContainerWindow::ScrollContainerWindow (Window* pParentWindow)
430     : Window(pParentWindow),
431       maSeparators()
432 {
433 #ifdef DEBUG
434     SetText(A2S("ScrollContainerWindow"));
435 #endif
436 }
437 
438 
439 
440 
441 Deck::ScrollContainerWindow::~ScrollContainerWindow (void)
442 {
443 }
444 
445 
446 
447 
448 void Deck::ScrollContainerWindow::Paint (const Rectangle& rUpdateArea)
449 {
450     (void)rUpdateArea;
451 
452     // Paint the separators.
453     const sal_Int32 nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
454     const sal_Int32 nLeft  (0);
455     const sal_Int32 nRight (GetSizePixel().Width()-1);
456     const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder));
457     for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end());
458          iY!=iEnd;
459          ++iY)
460     {
461         DrawHelper::DrawHorizontalLine(
462             *this,
463             nLeft,
464             nRight,
465             *iY,
466             nSeparatorHeight,
467             rHorizontalBorderPaint);
468     }
469 }
470 
471 
472 
473 
474 void Deck::ScrollContainerWindow::SetSeparators (const ::std::vector<sal_Int32>& rSeparators)
475 {
476     maSeparators = rSeparators;
477 }
478 
479 
480 } } // end of namespace sfx2::sidebar
481