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 <svtools/scrwin.hxx>
21 : #include <vcl/settings.hxx>
22 :
23 :
24 :
25 21 : void ScrollableWindow::ImpInitialize( ScrollableWindowFlags nFlags )
26 : {
27 21 : bHandleDragging = bool( nFlags & ScrollableWindowFlags::THUMBDRAGGING );
28 21 : bVCenter = bool(nFlags & ScrollableWindowFlags::VCENTER);
29 21 : bHCenter = bool(nFlags & ScrollableWindowFlags::HCENTER);
30 21 : bScrolling = false;
31 :
32 : // set the handlers for the scrollbars
33 21 : aVScroll->SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
34 21 : aHScroll->SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
35 21 : aVScroll->SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );
36 21 : aHScroll->SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );
37 :
38 21 : nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize();
39 21 : }
40 :
41 :
42 :
43 21 : ScrollableWindow::ScrollableWindow( vcl::Window* pParent, WinBits nBits,
44 : ScrollableWindowFlags nFlags ) :
45 : Window( pParent, WinBits(nBits|WB_CLIPCHILDREN) ),
46 : aVScroll( VclPtr<ScrollBar>::Create(this, WinBits(WB_VSCROLL | WB_DRAG)) ),
47 : aHScroll( VclPtr<ScrollBar>::Create(this, WinBits(WB_HSCROLL | WB_DRAG)) ),
48 21 : aCornerWin( VclPtr<ScrollBarBox>::Create(this) )
49 : {
50 21 : ImpInitialize( nFlags );
51 21 : }
52 :
53 :
54 42 : ScrollableWindow::~ScrollableWindow()
55 : {
56 21 : disposeOnce();
57 21 : }
58 :
59 21 : void ScrollableWindow::dispose()
60 : {
61 21 : aVScroll.disposeAndClear();
62 21 : aHScroll.disposeAndClear();
63 21 : aCornerWin.disposeAndClear();
64 21 : Window::dispose();
65 21 : }
66 :
67 :
68 0 : void ScrollableWindow::Command( const CommandEvent& rCEvt )
69 : {
70 0 : if ( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
71 0 : (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
72 0 : (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
73 : {
74 : ScrollBar* pHScrBar;
75 : ScrollBar* pVScrBar;
76 0 : if ( aHScroll->IsVisible() )
77 0 : pHScrBar = aHScroll.get();
78 : else
79 0 : pHScrBar = NULL;
80 0 : if ( aVScroll->IsVisible() )
81 0 : pVScrBar = aVScroll.get();
82 : else
83 0 : pVScrBar = NULL;
84 0 : if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) )
85 0 : return;
86 : }
87 :
88 0 : Window::Command( rCEvt );
89 : }
90 :
91 :
92 :
93 0 : void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt )
94 : {
95 0 : if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
96 0 : (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
97 : {
98 0 : Resize();
99 0 : Invalidate();
100 : }
101 :
102 0 : Window::DataChanged( rDCEvt );
103 0 : }
104 :
105 :
106 :
107 0 : Size ScrollableWindow::GetOutputSizePixel() const
108 : {
109 0 : Size aSz( Window::GetOutputSizePixel() );
110 :
111 0 : long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize();
112 0 : if ( aHScroll->IsVisible() )
113 0 : aSz.Height() -= nTmp;
114 0 : if ( aVScroll->IsVisible() )
115 0 : aSz.Width() -= nTmp;
116 0 : return aSz;
117 : }
118 :
119 :
120 :
121 0 : IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, pScroll )
122 : {
123 : // notify the start of scrolling, if not already scrolling
124 0 : if ( !bScrolling )
125 0 : bScrolling = true;
126 :
127 : // get the delta in logic coordinates
128 0 : Size aDelta( PixelToLogic( Size( aHScroll->GetDelta(), aVScroll->GetDelta() ) ) );
129 :
130 : // scroll the window, if this is not already done
131 0 : if ( !bHandleDragging )
132 : {
133 0 : if ( pScroll == aHScroll.get() )
134 0 : Scroll( aDelta.Width(), 0 );
135 : else
136 0 : Scroll( 0, aDelta.Height() );
137 : }
138 :
139 : // notify the end of scrolling
140 0 : bScrolling = false;
141 0 : return 0;
142 : }
143 :
144 :
145 :
146 0 : IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll )
147 : {
148 : // notify the start of scrolling, if not already scrolling
149 0 : if ( !bScrolling )
150 0 : bScrolling = true;
151 :
152 0 : if ( bHandleDragging )
153 : {
154 : // get the delta in logic coordinates
155 : Size aDelta( PixelToLogic(
156 0 : Size( aHScroll->GetDelta(), aVScroll->GetDelta() ) ) );
157 0 : if ( pScroll == aHScroll.get() )
158 0 : Scroll( aDelta.Width(), 0 );
159 : else
160 0 : Scroll( 0, aDelta.Height() );
161 : }
162 0 : return 0;
163 : }
164 :
165 :
166 :
167 68 : void ScrollableWindow::Resize()
168 : {
169 : // get the new output-size in pixel
170 68 : Size aOutPixSz = Window::GetOutputSizePixel();
171 :
172 : // determine the size of the output-area and if we need scrollbars
173 68 : const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize();
174 68 : bool bVVisible = false; // by default no vertical-ScrollBar
175 68 : bool bHVisible = false; // by default no horizontal-ScrollBar
176 : bool bChanged; // determines if a visiblility was changed
177 110 : do
178 : {
179 110 : bChanged = false;
180 :
181 : // does we need a vertical ScrollBar
182 110 : if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
183 : {
184 42 : bHVisible = true;
185 42 : aOutPixSz.Height() -= nScrSize;
186 42 : bChanged = true;
187 : }
188 :
189 : // does we need a horizontal ScrollBar
190 110 : if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
191 : {
192 42 : bVVisible = true;
193 42 : aOutPixSz.Width() -= nScrSize;
194 42 : bChanged = true;
195 : }
196 :
197 : }
198 : while ( bChanged ); // until no visibility has changed
199 :
200 : // store the old offset and map-mode
201 68 : MapMode aMap( GetMapMode() );
202 68 : Point aOldPixOffset( aPixOffset );
203 :
204 : // justify (right/bottom borders should never exceed the virtual window)
205 68 : Size aPixDelta;
206 68 : if ( aPixOffset.X() < 0 &&
207 0 : aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
208 0 : aPixDelta.Width() =
209 0 : aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() );
210 68 : if ( aPixOffset.Y() < 0 &&
211 0 : aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
212 0 : aPixDelta.Height() =
213 0 : aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() );
214 68 : if ( aPixDelta.Width() || aPixDelta.Height() )
215 : {
216 0 : aPixOffset.X() += aPixDelta.Width();
217 0 : aPixOffset.Y() += aPixDelta.Height();
218 : }
219 :
220 : // for axis without scrollbar restore the origin
221 68 : if ( !bVVisible || !bHVisible )
222 : {
223 : aPixOffset = Point(
224 : bHVisible
225 0 : ? aPixOffset.X()
226 : : ( bHCenter
227 26 : ? (aOutPixSz.Width()-aTotPixSz.Width()) / 2
228 : : 0 ),
229 : bVVisible
230 0 : ? aPixOffset.Y()
231 : : ( bVCenter
232 26 : ? (aOutPixSz.Height()-aTotPixSz.Height()) / 2
233 78 : : 0 ) );
234 : }
235 68 : if ( bHVisible && !aHScroll->IsVisible() )
236 21 : aPixOffset.X() = 0;
237 68 : if ( bVVisible && !aVScroll->IsVisible() )
238 21 : aPixOffset.Y() = 0;
239 :
240 : // select the shifted map-mode
241 68 : if ( aPixOffset != aOldPixOffset )
242 : {
243 26 : Window::SetMapMode( MapMode( MAP_PIXEL ) );
244 : Window::Scroll(
245 52 : aPixOffset.X() - aOldPixOffset.X(),
246 78 : aPixOffset.Y() - aOldPixOffset.Y() );
247 26 : SetMapMode( aMap );
248 : }
249 :
250 : // show or hide scrollbars
251 68 : aVScroll->Show( bVVisible );
252 68 : aHScroll->Show( bHVisible );
253 :
254 : // disable painting in the corner between the scrollbars
255 68 : if ( bVVisible && bHVisible )
256 : {
257 126 : aCornerWin->SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()),
258 126 : Size(nScrSize, nScrSize) );
259 42 : aCornerWin->Show();
260 : }
261 : else
262 26 : aCornerWin->Hide();
263 :
264 : // resize scrollbars and set their ranges
265 68 : if ( bHVisible )
266 : {
267 42 : aHScroll->SetPosSizePixel(
268 42 : Point( 0, aOutPixSz.Height() ),
269 84 : Size( aOutPixSz.Width(), nScrSize ) );
270 42 : aHScroll->SetRange( Range( 0, aTotPixSz.Width() ) );
271 42 : aHScroll->SetPageSize( aOutPixSz.Width() );
272 42 : aHScroll->SetVisibleSize( aOutPixSz.Width() );
273 42 : aHScroll->SetLineSize( nColumnPixW );
274 42 : aHScroll->SetThumbPos( -aPixOffset.X() );
275 : }
276 68 : if ( bVVisible )
277 : {
278 42 : aVScroll->SetPosSizePixel(
279 42 : Point( aOutPixSz.Width(), 0 ),
280 84 : Size( nScrSize,aOutPixSz.Height() ) );
281 42 : aVScroll->SetRange( Range( 0, aTotPixSz.Height() ) );
282 42 : aVScroll->SetPageSize( aOutPixSz.Height() );
283 42 : aVScroll->SetVisibleSize( aOutPixSz.Height() );
284 42 : aVScroll->SetLineSize( nLinePixH );
285 42 : aVScroll->SetThumbPos( -aPixOffset.Y() );
286 68 : }
287 68 : }
288 :
289 :
290 :
291 81 : void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode )
292 : {
293 81 : MapMode aMap( rNewMapMode );
294 81 : aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) );
295 81 : Window::SetMapMode( aMap );
296 81 : }
297 :
298 :
299 :
300 68 : MapMode ScrollableWindow::GetMapMode() const
301 : {
302 68 : MapMode aMap( Window::GetMapMode() );
303 68 : aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) );
304 68 : return aMap;
305 : }
306 :
307 :
308 :
309 30 : void ScrollableWindow::SetTotalSize( const Size& rNewSize )
310 : {
311 30 : aTotPixSz = LogicToPixel( rNewSize );
312 30 : ScrollableWindow::Resize();
313 30 : }
314 :
315 :
316 :
317 0 : void ScrollableWindow::Scroll( long nDeltaX, long nDeltaY, ScrollFlags )
318 : {
319 : // get the delta in pixel
320 0 : Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) );
321 0 : Size aOutPixSz( GetOutputSizePixel() );
322 0 : MapMode aMap( GetMapMode() );
323 0 : Point aNewPixOffset( aPixOffset );
324 :
325 : // scrolling horizontally?
326 0 : if ( nDeltaX != 0 )
327 : {
328 0 : aNewPixOffset.X() -= aDeltaPix.Width();
329 0 : if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() )
330 0 : aNewPixOffset.X() = - ( aTotPixSz.Width() - aOutPixSz.Width() );
331 0 : else if ( aNewPixOffset.X() > 0 )
332 0 : aNewPixOffset.X() = 0;
333 : }
334 :
335 : // scrolling vertically?
336 0 : if ( nDeltaY != 0 )
337 : {
338 0 : aNewPixOffset.Y() -= aDeltaPix.Height();
339 0 : if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() )
340 0 : aNewPixOffset.Y() = - ( aTotPixSz.Height() - aOutPixSz.Height() );
341 0 : else if ( aNewPixOffset.Y() > 0 )
342 0 : aNewPixOffset.Y() = 0;
343 : }
344 :
345 : // recompute the logical scroll units
346 0 : aDeltaPix.Width() = aPixOffset.X() - aNewPixOffset.X();
347 0 : aDeltaPix.Height() = aPixOffset.Y() - aNewPixOffset.Y();
348 0 : Size aDelta( PixelToLogic(aDeltaPix) );
349 0 : nDeltaX = aDelta.Width();
350 0 : nDeltaY = aDelta.Height();
351 0 : aPixOffset = aNewPixOffset;
352 :
353 : // scrolling?
354 0 : if ( nDeltaX != 0 || nDeltaY != 0 )
355 : {
356 0 : Update();
357 :
358 : // does the new area overlap the old one?
359 0 : if ( std::abs( (int)aDeltaPix.Height() ) < aOutPixSz.Height() ||
360 0 : std::abs( (int)aDeltaPix.Width() ) < aOutPixSz.Width() )
361 : {
362 : // scroll the overlapping area
363 0 : SetMapMode( aMap );
364 :
365 : // never scroll the scrollbars itself!
366 : Window::Scroll(-nDeltaX, -nDeltaY,
367 0 : PixelToLogic( Rectangle( Point(0, 0), aOutPixSz ) ) );
368 : }
369 : else
370 : {
371 : // repaint all
372 0 : SetMapMode( aMap );
373 0 : Invalidate();
374 : }
375 :
376 0 : Update();
377 : }
378 :
379 0 : if ( !bScrolling )
380 : {
381 0 : if ( nDeltaX )
382 0 : aHScroll->SetThumbPos( -aPixOffset.X() );
383 0 : if ( nDeltaY )
384 0 : aVScroll->SetThumbPos( -aPixOffset.Y() );
385 0 : }
386 0 : }
387 :
388 :
389 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|