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 <tools/rcid.h>
21 : #include <vcl/spin.h>
22 : #include <vcl/event.hxx>
23 : #include <vcl/spin.hxx>
24 : #include <vcl/settings.hxx>
25 :
26 1 : void SpinButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
27 : {
28 1 : mbUpperIn = false;
29 1 : mbLowerIn = false;
30 1 : mbInitialUp = false;
31 1 : mbInitialDown = false;
32 :
33 1 : mnMinRange = 0;
34 1 : mnMaxRange = 100;
35 1 : mnValue = 0;
36 1 : mnValueStep = 1;
37 :
38 1 : maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat());
39 1 : maRepeatTimer.SetTimeoutHdl(LINK(this, SpinButton, ImplTimeout));
40 :
41 1 : mbRepeat = 0 != (nStyle & WB_REPEAT);
42 :
43 1 : if (nStyle & WB_HSCROLL)
44 0 : mbHorz = true;
45 : else
46 1 : mbHorz = false;
47 :
48 1 : Control::ImplInit( pParent, nStyle, NULL );
49 1 : }
50 :
51 1 : SpinButton::SpinButton( vcl::Window* pParent, WinBits nStyle )
52 : : Control(WINDOW_SPINBUTTON)
53 1 : , mbUpperIsFocused(false)
54 : {
55 1 : ImplInit(pParent, nStyle);
56 1 : }
57 :
58 0 : IMPL_LINK_TYPED(SpinButton, ImplTimeout, Timer*, pTimer, void)
59 : {
60 0 : if (pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat())
61 : {
62 0 : pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
63 0 : pTimer->Start();
64 : }
65 : else
66 : {
67 0 : if (mbInitialUp)
68 0 : Up();
69 : else
70 0 : Down();
71 : }
72 0 : }
73 :
74 0 : void SpinButton::Up()
75 : {
76 0 : if (ImplIsUpperEnabled())
77 : {
78 0 : mnValue += mnValueStep;
79 0 : CompatStateChanged(StateChangedType::Data);
80 :
81 0 : ImplMoveFocus(true);
82 : }
83 :
84 0 : ImplCallEventListenersAndHandler(VCLEVENT_SPINBUTTON_UP, maUpHdlLink, this);
85 0 : }
86 :
87 0 : void SpinButton::Down()
88 : {
89 0 : if (ImplIsLowerEnabled())
90 : {
91 0 : mnValue -= mnValueStep;
92 0 : CompatStateChanged(StateChangedType::Data);
93 :
94 0 : ImplMoveFocus(false);
95 : }
96 :
97 0 : ImplCallEventListenersAndHandler(VCLEVENT_SPINBUTTON_DOWN, maDownHdlLink, this);
98 0 : }
99 :
100 2 : void SpinButton::Resize()
101 : {
102 2 : Control::Resize();
103 :
104 2 : Size aSize(GetOutputSizePixel());
105 2 : Point aTmpPoint;
106 2 : Rectangle aRect(aTmpPoint, aSize);
107 2 : if (mbHorz)
108 : {
109 2 : maLowerRect = Rectangle(0, 0, aSize.Width() / 2, aSize.Height() - 1);
110 2 : maUpperRect = Rectangle(maLowerRect.TopRight(), aRect.BottomRight());
111 : }
112 : else
113 : {
114 0 : maUpperRect = Rectangle(0, 0, aSize.Width() - 1, aSize.Height() / 2);
115 0 : maLowerRect = Rectangle(maUpperRect.BottomLeft(), aRect.BottomRight());
116 : }
117 :
118 2 : ImplCalcFocusRect(ImplIsUpperEnabled() || !ImplIsLowerEnabled());
119 :
120 2 : Invalidate();
121 2 : }
122 :
123 0 : void SpinButton::Draw(OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags)
124 : {
125 0 : Point aPos = pDev->LogicToPixel(rPos);
126 0 : Size aSize = pDev->LogicToPixel(rSize);
127 :
128 0 : pDev->Push();
129 0 : pDev->SetMapMode();
130 0 : if ( !(nFlags & DrawFlags::Mono) )
131 : {
132 : // DecoView uses the FaceColor...
133 0 : AllSettings aSettings = pDev->GetSettings();
134 0 : StyleSettings aStyleSettings = aSettings.GetStyleSettings();
135 0 : if ( IsControlBackground() )
136 0 : aStyleSettings.SetFaceColor( GetControlBackground() );
137 : else
138 0 : aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
139 :
140 0 : aSettings.SetStyleSettings( aStyleSettings );
141 0 : pDev->SetSettings( aSettings );
142 : }
143 :
144 0 : Rectangle aRect( Point( 0, 0 ), aSize );
145 0 : Rectangle aLowerRect, aUpperRect;
146 0 : if ( mbHorz )
147 : {
148 0 : aLowerRect = Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
149 0 : aUpperRect = Rectangle( aLowerRect.TopRight(), aRect.BottomRight() );
150 : }
151 : else
152 : {
153 0 : aUpperRect = Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
154 0 : aLowerRect = Rectangle( aUpperRect.BottomLeft(), aRect.BottomRight() );
155 : }
156 :
157 0 : aUpperRect += aPos;
158 0 : aLowerRect += aPos;
159 :
160 : ImplDrawSpinButton(*pDev, this, aUpperRect, aLowerRect, false, false,
161 0 : IsEnabled() && ImplIsUpperEnabled(),
162 0 : IsEnabled() && ImplIsLowerEnabled(), mbHorz, true);
163 0 : pDev->Pop();
164 0 : }
165 :
166 4 : void SpinButton::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rRect*/)
167 : {
168 4 : HideFocus();
169 :
170 4 : bool bEnable = IsEnabled();
171 : ImplDrawSpinButton(rRenderContext, this, maUpperRect, maLowerRect, mbUpperIn, mbLowerIn,
172 4 : bEnable && ImplIsUpperEnabled(),
173 8 : bEnable && ImplIsLowerEnabled(), mbHorz, true);
174 :
175 4 : if (HasFocus())
176 0 : ShowFocus(maFocusRect);
177 4 : }
178 :
179 0 : void SpinButton::MouseButtonDown( const MouseEvent& rMEvt )
180 : {
181 0 : if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsUpperEnabled() ) )
182 : {
183 0 : mbUpperIn = true;
184 0 : mbInitialUp = true;
185 0 : Invalidate( maUpperRect );
186 : }
187 0 : else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsLowerEnabled() ) )
188 : {
189 0 : mbLowerIn = true;
190 0 : mbInitialDown = true;
191 0 : Invalidate( maLowerRect );
192 : }
193 :
194 0 : if ( mbUpperIn || mbLowerIn )
195 : {
196 0 : Update();
197 0 : CaptureMouse();
198 0 : if ( mbRepeat )
199 0 : maRepeatTimer.Start();
200 : }
201 0 : }
202 :
203 0 : void SpinButton::MouseButtonUp( const MouseEvent& )
204 : {
205 0 : ReleaseMouse();
206 0 : if ( mbRepeat )
207 : {
208 0 : maRepeatTimer.Stop();
209 0 : maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat() );
210 : }
211 :
212 0 : if ( mbUpperIn )
213 : {
214 0 : mbUpperIn = false;
215 0 : Invalidate( maUpperRect );
216 0 : Update();
217 0 : Up();
218 : }
219 0 : else if ( mbLowerIn )
220 : {
221 0 : mbLowerIn = false;
222 0 : Invalidate( maLowerRect );
223 0 : Update();
224 0 : Down();
225 : }
226 :
227 0 : mbInitialUp = mbInitialDown = false;
228 0 : }
229 :
230 0 : void SpinButton::MouseMove( const MouseEvent& rMEvt )
231 : {
232 0 : if ( !rMEvt.IsLeft() || (!mbInitialUp && !mbInitialDown) )
233 0 : return;
234 :
235 0 : if ( !maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
236 0 : mbUpperIn && mbInitialUp )
237 : {
238 0 : mbUpperIn = false;
239 0 : maRepeatTimer.Stop();
240 0 : Invalidate( maUpperRect );
241 0 : Update();
242 : }
243 0 : else if ( !maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
244 0 : mbLowerIn && mbInitialDown )
245 : {
246 0 : mbLowerIn = false;
247 0 : maRepeatTimer.Stop();
248 0 : Invalidate( maLowerRect );
249 0 : Update();
250 : }
251 0 : else if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
252 0 : !mbUpperIn && mbInitialUp )
253 : {
254 0 : mbUpperIn = true;
255 0 : if ( mbRepeat )
256 0 : maRepeatTimer.Start();
257 0 : Invalidate( maUpperRect );
258 0 : Update();
259 : }
260 0 : else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
261 0 : !mbLowerIn && mbInitialDown )
262 : {
263 0 : mbLowerIn = true;
264 0 : if ( mbRepeat )
265 0 : maRepeatTimer.Start();
266 0 : Invalidate( maLowerRect );
267 0 : Update();
268 : }
269 : }
270 :
271 0 : void SpinButton::KeyInput( const KeyEvent& rKEvt )
272 : {
273 0 : if ( !rKEvt.GetKeyCode().GetModifier() )
274 : {
275 0 : switch ( rKEvt.GetKeyCode().GetCode() )
276 : {
277 : case KEY_LEFT:
278 : case KEY_RIGHT:
279 : {
280 0 : bool bUp = KEY_RIGHT == rKEvt.GetKeyCode().GetCode();
281 0 : if ( mbHorz && !ImplMoveFocus( bUp ) )
282 0 : bUp ? Up() : Down();
283 : }
284 0 : break;
285 :
286 : case KEY_UP:
287 : case KEY_DOWN:
288 : {
289 0 : bool bUp = KEY_UP == rKEvt.GetKeyCode().GetCode();
290 0 : if ( !mbHorz && !ImplMoveFocus( KEY_UP == rKEvt.GetKeyCode().GetCode() ) )
291 0 : bUp ? Up() : Down();
292 : }
293 0 : break;
294 :
295 : case KEY_SPACE:
296 0 : mbUpperIsFocused ? Up() : Down();
297 0 : break;
298 :
299 : default:
300 0 : Control::KeyInput( rKEvt );
301 0 : break;
302 : }
303 : }
304 : else
305 0 : Control::KeyInput( rKEvt );
306 0 : }
307 :
308 13 : void SpinButton::StateChanged( StateChangedType nType )
309 : {
310 13 : switch ( nType )
311 : {
312 : case StateChangedType::Data:
313 : case StateChangedType::Enable:
314 0 : Invalidate();
315 0 : break;
316 :
317 : case StateChangedType::Style:
318 : {
319 2 : bool bNewRepeat = 0 != ( GetStyle() & WB_REPEAT );
320 2 : if ( bNewRepeat != mbRepeat )
321 : {
322 1 : if ( maRepeatTimer.IsActive() )
323 : {
324 0 : maRepeatTimer.Stop();
325 0 : maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
326 : }
327 1 : mbRepeat = bNewRepeat;
328 : }
329 :
330 2 : bool bNewHorz = 0 != ( GetStyle() & WB_HSCROLL );
331 2 : if ( bNewHorz != mbHorz )
332 : {
333 1 : mbHorz = bNewHorz;
334 1 : Resize();
335 : }
336 : }
337 2 : break;
338 : default:;
339 : }
340 :
341 13 : Control::StateChanged( nType );
342 13 : }
343 :
344 1 : void SpinButton::SetRangeMin( long nNewRange )
345 : {
346 1 : SetRange( Range( nNewRange, GetRangeMax() ) );
347 1 : }
348 :
349 1 : void SpinButton::SetRangeMax( long nNewRange )
350 : {
351 1 : SetRange( Range( GetRangeMin(), nNewRange ) );
352 1 : }
353 :
354 2 : void SpinButton::SetRange( const Range& rRange )
355 : {
356 : // adjust rage
357 2 : Range aRange = rRange;
358 2 : aRange.Justify();
359 2 : long nNewMinRange = aRange.Min();
360 2 : long nNewMaxRange = aRange.Max();
361 :
362 : // do something only if old and new range differ
363 4 : if ( (mnMinRange != nNewMinRange) ||
364 2 : (mnMaxRange != nNewMaxRange) )
365 : {
366 0 : mnMinRange = nNewMinRange;
367 0 : mnMaxRange = nNewMaxRange;
368 :
369 : // adjust value to new range, if necessary
370 0 : if ( mnValue > mnMaxRange )
371 0 : mnValue = mnMaxRange;
372 0 : if ( mnValue < mnMinRange )
373 0 : mnValue = mnMinRange;
374 :
375 0 : CompatStateChanged( StateChangedType::Data );
376 : }
377 2 : }
378 :
379 1 : void SpinButton::SetValue( long nValue )
380 : {
381 : // adjust, if necessary
382 1 : if ( nValue > mnMaxRange )
383 0 : nValue = mnMaxRange;
384 1 : if ( nValue < mnMinRange )
385 0 : nValue = mnMinRange;
386 :
387 1 : if ( mnValue != nValue )
388 : {
389 0 : mnValue = nValue;
390 0 : CompatStateChanged( StateChangedType::Data );
391 : }
392 1 : }
393 :
394 0 : void SpinButton::GetFocus()
395 : {
396 0 : ShowFocus( maFocusRect );
397 0 : Control::GetFocus();
398 0 : }
399 :
400 0 : void SpinButton::LoseFocus()
401 : {
402 0 : HideFocus();
403 0 : Control::LoseFocus();
404 0 : }
405 :
406 0 : bool SpinButton::ImplMoveFocus( bool _bUpper )
407 : {
408 0 : if ( _bUpper == mbUpperIsFocused )
409 0 : return false;
410 :
411 0 : HideFocus();
412 0 : ImplCalcFocusRect( _bUpper );
413 0 : if ( HasFocus() )
414 0 : ShowFocus( maFocusRect );
415 0 : return true;
416 : }
417 :
418 2 : void SpinButton::ImplCalcFocusRect( bool _bUpper )
419 : {
420 2 : maFocusRect = _bUpper ? maUpperRect : maLowerRect;
421 : // inflate by some pixels
422 2 : maFocusRect.Left() += 2;
423 2 : maFocusRect.Top() += 2;
424 2 : maFocusRect.Right() -= 2;
425 2 : maFocusRect.Bottom() -= 2;
426 2 : mbUpperIsFocused = _bUpper;
427 2 : }
428 :
429 0 : Rectangle* SpinButton::ImplFindPartRect( const Point& rPt )
430 : {
431 0 : if( maUpperRect.IsInside( rPt ) )
432 0 : return &maUpperRect;
433 0 : else if( maLowerRect.IsInside( rPt ) )
434 0 : return &maLowerRect;
435 : else
436 0 : return NULL;
437 : }
438 :
439 0 : bool SpinButton::PreNotify( NotifyEvent& rNEvt )
440 : {
441 0 : const MouseEvent* pMouseEvt = NULL;
442 :
443 0 : if ((rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL)
444 : {
445 0 : if (!pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged())
446 : {
447 : // trigger redraw if mouse over state has changed
448 0 : if (IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
449 0 : IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
450 : {
451 0 : Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
452 0 : Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
453 0 : if (pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()))
454 : {
455 0 : vcl::Region aRgn(GetActiveClipRegion());
456 0 : if (pLastRect)
457 : {
458 0 : SetClipRegion(vcl::Region(*pLastRect));
459 0 : Invalidate(*pLastRect);
460 0 : SetClipRegion( aRgn );
461 : }
462 0 : if (pRect)
463 : {
464 0 : SetClipRegion(vcl::Region(*pRect));
465 0 : Invalidate(*pRect);
466 0 : SetClipRegion(aRgn);
467 0 : }
468 : }
469 : }
470 : }
471 : }
472 :
473 0 : return Control::PreNotify(rNEvt);
474 : }
475 :
476 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|