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