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 : using namespace css;
36 : using namespace css::uno;
37 :
38 : namespace sfx2 { namespace sidebar {
39 :
40 3156 : Deck::Deck(const DeckDescriptor& rDeckDescriptor, vcl::Window* pParentWindow,
41 : const std::function<void()>& rCloserAction)
42 : : Window(pParentWindow, 0)
43 : , msId(rDeckDescriptor.msId)
44 : , maIcon()
45 : , mnMinimalWidth(0)
46 : , maPanels()
47 : , mpTitleBar(VclPtr<DeckTitleBar>::Create(rDeckDescriptor.msTitle, this, rCloserAction))
48 : , mpScrollClipWindow(VclPtr<vcl::Window>::Create(this))
49 3156 : , mpScrollContainer(VclPtr<ScrollContainerWindow>::Create(mpScrollClipWindow.get()))
50 : , mpFiller(VclPtr<vcl::Window>::Create(this))
51 6312 : , mpVerticalScrollBar(VclPtr<ScrollBar>::Create(this))
52 : {
53 3156 : mpScrollClipWindow->SetBackground(Wallpaper());
54 3156 : mpScrollClipWindow->Show();
55 :
56 3156 : mpScrollContainer->SetStyle(mpScrollContainer->GetStyle() | WB_DIALOGCONTROL);
57 3156 : mpScrollContainer->SetBackground(Wallpaper());
58 3156 : mpScrollContainer->Show();
59 :
60 3156 : mpVerticalScrollBar->SetScrollHdl(LINK(this, Deck, HandleVerticalScrollBarChange));
61 :
62 : #ifdef DEBUG
63 : SetText(OUString("Deck"));
64 : mpScrollClipWindow->SetText(OUString("ScrollClipWindow"));
65 : mpFiller->SetText(OUString("Filler"));
66 : mpVerticalScrollBar->SetText(OUString("VerticalScrollBar"));
67 : #endif
68 3156 : }
69 :
70 9468 : Deck::~Deck()
71 : {
72 3156 : disposeOnce();
73 6312 : }
74 :
75 3156 : void Deck::dispose()
76 : {
77 3156 : SharedPanelContainer aPanels;
78 3156 : aPanels.swap(maPanels);
79 :
80 : // We have to explicitly trigger the destruction of panels.
81 : // Otherwise that is done by one of our base class destructors
82 : // without updating maPanels.
83 6879 : for (size_t i = 0; i < aPanels.size(); i++)
84 3723 : aPanels[i].disposeAndClear();
85 :
86 3156 : mpTitleBar.disposeAndClear();
87 3156 : mpFiller.disposeAndClear();
88 3156 : mpVerticalScrollBar.disposeAndClear();
89 3156 : mpScrollContainer.disposeAndClear();
90 3156 : mpScrollClipWindow.disposeAndClear();
91 :
92 3156 : vcl::Window::dispose();
93 3156 : }
94 :
95 33558 : DeckTitleBar* Deck::GetTitleBar() const
96 : {
97 33558 : return mpTitleBar.get();
98 : }
99 :
100 6245 : Rectangle Deck::GetContentArea() const
101 : {
102 6245 : const Size aWindowSize (GetSizePixel());
103 6245 : const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize));
104 :
105 : return Rectangle(
106 6245 : Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize,
107 6245 : Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize,
108 6245 : aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize,
109 24980 : aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize);
110 : }
111 :
112 137 : void Deck::ApplySettings(vcl::RenderContext& rRenderContext)
113 : {
114 137 : rRenderContext.SetBackground(Wallpaper());
115 137 : }
116 :
117 137 : void Deck::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rUpdateArea*/)
118 : {
119 137 : const Size aWindowSize (GetSizePixel());
120 137 : const SvBorder aPadding(Theme::GetInteger(Theme::Int_DeckLeftPadding),
121 137 : Theme::GetInteger(Theme::Int_DeckTopPadding),
122 137 : Theme::GetInteger(Theme::Int_DeckRightPadding),
123 548 : Theme::GetInteger(Theme::Int_DeckBottomPadding));
124 :
125 : // Paint deck background outside the border.
126 137 : Rectangle aBox(0, 0, aWindowSize.Width() - 1, aWindowSize.Height() - 1);
127 : DrawHelper::DrawBorder(rRenderContext, aBox, aPadding,
128 137 : Theme::GetPaint(Theme::Paint_DeckBackground),
129 274 : Theme::GetPaint(Theme::Paint_DeckBackground));
130 :
131 : // Paint the border.
132 137 : const int nBorderSize(Theme::GetInteger(Theme::Int_DeckBorderSize));
133 137 : aBox.Left() += aPadding.Left();
134 137 : aBox.Top() += aPadding.Top();
135 137 : aBox.Right() -= aPadding.Right();
136 137 : aBox.Bottom() -= aPadding.Bottom();
137 137 : const sfx2::sidebar::Paint& rHorizontalBorderPaint(Theme::GetPaint(Theme::Paint_HorizontalBorder));
138 : DrawHelper::DrawBorder(rRenderContext, aBox,
139 : SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize),
140 : rHorizontalBorderPaint,
141 137 : Theme::GetPaint(Theme::Paint_VerticalBorder));
142 137 : }
143 :
144 3 : void Deck::DataChanged (const DataChangedEvent& rEvent)
145 : {
146 : (void)rEvent;
147 3 : RequestLayout();
148 3 : }
149 :
150 74581 : bool Deck::Notify (NotifyEvent& rEvent)
151 : {
152 74581 : if (rEvent.GetType() == MouseNotifyEvent::COMMAND)
153 : {
154 0 : CommandEvent* pCommandEvent = static_cast<CommandEvent*>(rEvent.GetData());
155 0 : if (pCommandEvent != NULL)
156 0 : switch (pCommandEvent->GetCommand())
157 : {
158 : case CommandEventId::Wheel:
159 0 : return ProcessWheelEvent(pCommandEvent);
160 :
161 : default:
162 0 : break;
163 : }
164 : }
165 :
166 74581 : return Window::Notify(rEvent);
167 : }
168 :
169 0 : bool Deck::ProcessWheelEvent(CommandEvent* pCommandEvent)
170 : {
171 0 : if ( ! mpVerticalScrollBar)
172 0 : return false;
173 0 : if ( ! mpVerticalScrollBar->IsVisible())
174 0 : return false;
175 :
176 : // Get the wheel data and check that it describes a valid vertical
177 : // scroll.
178 0 : const CommandWheelData* pData = pCommandEvent->GetWheelData();
179 0 : if (pData==NULL
180 0 : || pData->GetModifier()
181 0 : || pData->GetMode() != CommandWheelMode::SCROLL
182 0 : || pData->IsHorz())
183 0 : return false;
184 :
185 : // Execute the actual scroll action.
186 0 : long nDelta = pData->GetDelta();
187 : mpVerticalScrollBar->DoScroll(
188 0 : mpVerticalScrollBar->GetThumbPos() - nDelta);
189 0 : return true;
190 : }
191 :
192 : /**
193 : * This container may contain existing panels that are
194 : * being re-used, and new ones too.
195 : */
196 3765 : void Deck::ResetPanels(const SharedPanelContainer& rPanels)
197 : {
198 : // First dispose old panels we no longer need.
199 4415 : for (size_t i = 0; i < maPanels.size(); i++)
200 : {
201 650 : bool bFound = false;
202 2609 : for (size_t j = 0; j < rPanels.size(); j++)
203 1959 : bFound = bFound || (maPanels[i].get() == rPanels[j].get());
204 650 : if (!bFound) // this one didn't survive.
205 525 : maPanels[i].disposeAndClear();
206 : }
207 3765 : maPanels = rPanels;
208 :
209 3765 : RequestLayout();
210 3765 : }
211 :
212 6245 : void Deck::RequestLayout()
213 : {
214 6245 : mnMinimalWidth = 0;
215 :
216 : DeckLayouter::LayoutDeck(GetContentArea(), mnMinimalWidth, maPanels,
217 12490 : *GetTitleBar(), *mpScrollClipWindow, *mpScrollContainer,
218 18735 : *mpFiller, *mpVerticalScrollBar);
219 6245 : }
220 :
221 4927 : vcl::Window* Deck::GetPanelParentWindow()
222 : {
223 4927 : return mpScrollContainer.get();
224 : }
225 :
226 0 : void Deck::ShowPanel(const Panel& rPanel)
227 : {
228 0 : if (mpVerticalScrollBar && mpVerticalScrollBar->IsVisible())
229 : {
230 : // Get vertical extent of the panel.
231 0 : sal_Int32 nPanelTop (rPanel.GetPosPixel().Y());
232 0 : const sal_Int32 nPanelBottom (nPanelTop + rPanel.GetSizePixel().Height() - 1);
233 : // Add the title bar into the extent.
234 0 : if (rPanel.GetTitleBar() != NULL && rPanel.GetTitleBar()->IsVisible())
235 0 : nPanelTop = rPanel.GetTitleBar()->GetPosPixel().Y();
236 :
237 : // Determine what the new thumb position should be like.
238 : // When the whole panel does not fit then make its top visible
239 : // and it off at the bottom.
240 0 : sal_Int32 nNewThumbPos (mpVerticalScrollBar->GetThumbPos());
241 0 : if (nPanelBottom >= nNewThumbPos+mpVerticalScrollBar->GetVisibleSize())
242 0 : nNewThumbPos = nPanelBottom - mpVerticalScrollBar->GetVisibleSize();
243 0 : if (nPanelTop < nNewThumbPos)
244 0 : nNewThumbPos = nPanelTop;
245 :
246 0 : mpVerticalScrollBar->SetThumbPos(nNewThumbPos);
247 0 : mpScrollContainer->SetPosPixel(
248 : Point(
249 0 : mpScrollContainer->GetPosPixel().X(),
250 0 : -nNewThumbPos));
251 :
252 : }
253 0 : }
254 :
255 0 : const OUString GetWindowClassification(const vcl::Window* pWindow)
256 : {
257 0 : const OUString& rsName (pWindow->GetText());
258 0 : if (!rsName.isEmpty())
259 : {
260 0 : return rsName;
261 : }
262 : else
263 : {
264 0 : return OUString("window");
265 0 : }
266 : }
267 :
268 0 : void Deck::PrintWindowSubTree(vcl::Window* pRoot, int nIndentation)
269 : {
270 : static const char* sIndentation = " ";
271 0 : const Point aLocation (pRoot->GetPosPixel());
272 0 : const Size aSize (pRoot->GetSizePixel());
273 : SAL_INFO(
274 : "sfx.sidebar",
275 : sIndentation + strlen(sIndentation) - nIndentation * 4 << pRoot << " "
276 : << GetWindowClassification(pRoot) << " "
277 : << (pRoot->IsVisible() ? "visible" : "hidden") << " +"
278 : << aLocation.X() << "+" << aLocation.Y() << " x" << aSize.Width()
279 : << "x" << aSize.Height());
280 :
281 0 : const sal_uInt16 nChildCount(pRoot->GetChildCount());
282 0 : for (sal_uInt16 nIndex = 0; nIndex < nChildCount; ++nIndex)
283 0 : PrintWindowSubTree(pRoot->GetChild(nIndex), nIndentation + 1);
284 0 : }
285 :
286 0 : IMPL_LINK_NOARG(Deck, HandleVerticalScrollBarChange)
287 : {
288 0 : const sal_Int32 nYOffset (-mpVerticalScrollBar->GetThumbPos());
289 0 : mpScrollContainer->SetPosPixel(Point(mpScrollContainer->GetPosPixel().X(),
290 0 : nYOffset));
291 0 : return sal_IntPtr(true);
292 : }
293 :
294 : //----- Deck::ScrollContainerWindow -------------------------------------------
295 :
296 3156 : Deck::ScrollContainerWindow::ScrollContainerWindow (vcl::Window* pParentWindow)
297 : : Window(pParentWindow),
298 3156 : maSeparators()
299 : {
300 : #ifdef DEBUG
301 : SetText(OUString("ScrollContainerWindow"));
302 : #endif
303 3156 : }
304 :
305 137 : void Deck::ScrollContainerWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rUpdateArea*/)
306 : {
307 : // Paint the separators.
308 137 : const sal_Int32 nSeparatorHeight(Theme::GetInteger(Theme::Int_DeckSeparatorHeight));
309 137 : const sal_Int32 nLeft(0);
310 137 : const sal_Int32 nRight(GetSizePixel().Width() - 1);
311 137 : const sfx2::sidebar::Paint& rHorizontalBorderPaint(Theme::GetPaint(Theme::Paint_HorizontalBorder));
312 279 : for (std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()); iY != maSeparators.end(); ++iY)
313 : {
314 142 : DrawHelper::DrawHorizontalLine(rRenderContext, nLeft, nRight, *iY,
315 142 : nSeparatorHeight, rHorizontalBorderPaint);
316 : }
317 137 : }
318 :
319 2703 : void Deck::ScrollContainerWindow::SetSeparators (const ::std::vector<sal_Int32>& rSeparators)
320 : {
321 2703 : maSeparators = rSeparators;
322 2703 : }
323 :
324 648 : } } // end of namespace sfx2::sidebar
325 :
326 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|