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