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 :
21 : #include "tools/rc.h"
22 :
23 : #include "vcl/event.hxx"
24 : #include "vcl/decoview.hxx"
25 : #include "vcl/spin.h"
26 : #include "vcl/spinfld.hxx"
27 :
28 : #include "controldata.hxx"
29 : #include "svdata.hxx"
30 :
31 : // =======================================================================
32 :
33 0 : void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
34 : const Rectangle& rLowerRect,
35 : sal_Bool bUpperIn, sal_Bool bLowerIn,
36 : sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz,
37 : SpinbuttonValue& rValue )
38 : {
39 : // convert spinbutton data to a SpinbuttonValue structure for native painting
40 :
41 0 : rValue.maUpperRect = rUpperRect;
42 0 : rValue.maLowerRect = rLowerRect;
43 :
44 0 : Point aPointerPos = pWin->GetPointerPosPixel();
45 :
46 0 : ControlState nState = CTRL_STATE_ENABLED;
47 0 : if ( bUpperIn )
48 0 : nState |= CTRL_STATE_PRESSED;
49 0 : if ( !pWin->IsEnabled() || !bUpperEnabled )
50 0 : nState &= ~CTRL_STATE_ENABLED;
51 0 : if ( pWin->HasFocus() )
52 0 : nState |= CTRL_STATE_FOCUSED;
53 0 : if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
54 0 : nState |= CTRL_STATE_ROLLOVER;
55 0 : rValue.mnUpperState = nState;
56 :
57 0 : nState = CTRL_STATE_ENABLED;
58 0 : if ( bLowerIn )
59 0 : nState |= CTRL_STATE_PRESSED;
60 0 : if ( !pWin->IsEnabled() || !bLowerEnabled )
61 0 : nState &= ~CTRL_STATE_ENABLED;
62 0 : if ( pWin->HasFocus() )
63 0 : nState |= CTRL_STATE_FOCUSED;
64 : // for overlapping spins: highlight only one
65 0 : if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
66 0 : !rUpperRect.IsInside( aPointerPos ) )
67 0 : nState |= CTRL_STATE_ROLLOVER;
68 0 : rValue.mnLowerState = nState;
69 :
70 0 : rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
71 0 : rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
72 0 : }
73 :
74 :
75 0 : sal_Bool ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
76 : {
77 0 : sal_Bool bNativeOK = sal_False;
78 :
79 0 : if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
80 : // there is just no useful native support for spinfields with dropdown
81 0 : !(pWin->GetStyle() & WB_DROPDOWN) )
82 : {
83 0 : if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
84 0 : pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
85 : {
86 : // only paint the embedded spin buttons, all buttons are painted at once
87 : bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
88 0 : rSpinbuttonValue, rtl::OUString() );
89 : }
90 : else
91 : {
92 : // paint the spinbox as a whole, use borderwindow to have proper clipping
93 0 : Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
94 :
95 : // to not overwrite everything, set the button region as clipregion to the border window
96 0 : Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
97 0 : aClipRect.Union( rSpinbuttonValue.maUpperRect );
98 :
99 : // convert from screen space to borderwin space
100 0 : aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
101 :
102 0 : Region oldRgn( pBorder->GetClipRegion() );
103 0 : pBorder->SetClipRegion( Region( aClipRect ) );
104 :
105 0 : Point aPt;
106 0 : Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
107 0 : Rectangle aBound, aContent;
108 0 : Rectangle aNatRgn( aPt, aSize );
109 0 : if( ! ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize &&
110 : pBorder->GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL,
111 0 : aNatRgn, 0, rSpinbuttonValue, rtl::OUString(), aBound, aContent) )
112 : {
113 0 : aSize = aContent.GetSize();
114 : }
115 :
116 0 : Rectangle aRgn( aPt, aSize );
117 : bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
118 0 : rSpinbuttonValue, rtl::OUString() );
119 :
120 0 : pBorder->SetClipRegion( oldRgn );
121 : }
122 : }
123 0 : return bNativeOK;
124 : }
125 :
126 0 : sal_Bool ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
127 : {
128 0 : sal_Bool bNativeOK = sal_False;
129 :
130 0 : if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
131 : {
132 : // only paint the standalone spin buttons, all buttons are painted at once
133 : bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
134 0 : rSpinbuttonValue, rtl::OUString() );
135 : }
136 0 : return bNativeOK;
137 : }
138 :
139 0 : void ImplDrawSpinButton( OutputDevice* pOutDev,
140 : const Rectangle& rUpperRect,
141 : const Rectangle& rLowerRect,
142 : sal_Bool bUpperIn, sal_Bool bLowerIn,
143 : sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz, sal_Bool bMirrorHorz )
144 : {
145 0 : DecorationView aDecoView( pOutDev );
146 :
147 0 : sal_uInt16 nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
148 0 : sal_uInt16 nSymStyle = 0;
149 :
150 : SymbolType eType1, eType2;
151 :
152 0 : const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
153 0 : if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
154 : {
155 : // arrows are only use in OS/2 look
156 0 : if ( bHorz )
157 : {
158 0 : eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
159 0 : eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
160 : }
161 : else
162 : {
163 0 : eType1 = SYMBOL_ARROW_UP;
164 0 : eType2 = SYMBOL_ARROW_DOWN;
165 : }
166 : }
167 : else
168 : {
169 0 : if ( bHorz )
170 : {
171 0 : eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
172 0 : eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
173 : }
174 : else
175 : {
176 0 : eType1 = SYMBOL_SPIN_UP;
177 0 : eType2 = SYMBOL_SPIN_DOWN;
178 : }
179 : }
180 :
181 : // Oberen/linken Button malen
182 0 : sal_uInt16 nTempStyle = nStyle;
183 0 : if ( bUpperIn )
184 0 : nTempStyle |= BUTTON_DRAW_PRESSED;
185 :
186 0 : sal_Bool bNativeOK = sal_False;
187 0 : Rectangle aUpRect;
188 :
189 0 : if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
190 : {
191 0 : Window *pWin = (Window*) pOutDev;
192 :
193 : // are we drawing standalone spin buttons or members of a spinfield ?
194 0 : ControlType aControl = CTRL_SPINBUTTONS;
195 0 : switch( pWin->GetType() )
196 : {
197 : case WINDOW_EDIT:
198 : case WINDOW_MULTILINEEDIT:
199 : case WINDOW_PATTERNFIELD:
200 : case WINDOW_METRICFIELD:
201 : case WINDOW_CURRENCYFIELD:
202 : case WINDOW_DATEFIELD:
203 : case WINDOW_TIMEFIELD:
204 : case WINDOW_LONGCURRENCYFIELD:
205 : case WINDOW_NUMERICFIELD:
206 : case WINDOW_SPINFIELD:
207 0 : aControl = CTRL_SPINBOX;
208 0 : break;
209 : default:
210 0 : aControl = CTRL_SPINBUTTONS;
211 0 : break;
212 : }
213 :
214 0 : SpinbuttonValue aValue;
215 : ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
216 : bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
217 0 : bHorz, aValue );
218 :
219 0 : if( aControl == CTRL_SPINBOX )
220 0 : bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
221 0 : else if( aControl == CTRL_SPINBUTTONS )
222 0 : bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
223 : }
224 :
225 0 : if( !bNativeOK )
226 0 : aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
227 :
228 : // Unteren/rechten Button malen
229 0 : if ( bLowerIn )
230 0 : nStyle |= BUTTON_DRAW_PRESSED;
231 0 : Rectangle aLowRect;
232 0 : if( !bNativeOK )
233 0 : aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
234 :
235 : // Zusaetzliche Default-Kante wollen wir auch ausnutzen
236 0 : aUpRect.Left()--;
237 0 : aUpRect.Top()--;
238 0 : aUpRect.Right()++;
239 0 : aUpRect.Bottom()++;
240 0 : aLowRect.Left()--;
241 0 : aLowRect.Top()--;
242 0 : aLowRect.Right()++;
243 0 : aLowRect.Bottom()++;
244 :
245 : // Wir malen auch in die Kante rein, damit man etwas erkennen kann,
246 : // wenn das Rechteck zu klein ist
247 0 : if ( aUpRect.GetHeight() < 4 )
248 : {
249 0 : aUpRect.Right()++;
250 0 : aUpRect.Bottom()++;
251 0 : aLowRect.Right()++;
252 0 : aLowRect.Bottom()++;
253 : }
254 :
255 : // Symbolgroesse berechnen
256 0 : long nTempSize1 = aUpRect.GetWidth();
257 0 : long nTempSize2 = aLowRect.GetWidth();
258 0 : if ( Abs( nTempSize1-nTempSize2 ) == 1 )
259 : {
260 0 : if ( nTempSize1 > nTempSize2 )
261 0 : aUpRect.Left()++;
262 : else
263 0 : aLowRect.Left()++;
264 : }
265 0 : nTempSize1 = aUpRect.GetHeight();
266 0 : nTempSize2 = aLowRect.GetHeight();
267 0 : if ( Abs( nTempSize1-nTempSize2 ) == 1 )
268 : {
269 0 : if ( nTempSize1 > nTempSize2 )
270 0 : aUpRect.Top()++;
271 : else
272 0 : aLowRect.Top()++;
273 : }
274 :
275 0 : nTempStyle = nSymStyle;
276 0 : if ( !bUpperEnabled )
277 0 : nTempStyle |= SYMBOL_DRAW_DISABLE;
278 0 : if( !bNativeOK )
279 0 : aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
280 :
281 0 : if ( !bLowerEnabled )
282 0 : nSymStyle |= SYMBOL_DRAW_DISABLE;
283 0 : if( !bNativeOK )
284 0 : aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
285 0 : }
286 :
287 : // =======================================================================
288 :
289 0 : void SpinField::ImplInitSpinFieldData()
290 : {
291 0 : mpEdit = NULL;
292 0 : mbSpin = sal_False;
293 0 : mbRepeat = sal_False;
294 0 : mbUpperIn = sal_False;
295 0 : mbLowerIn = sal_False;
296 0 : mbInitialUp = sal_False;
297 0 : mbInitialDown = sal_False;
298 0 : mbNoSelect = sal_False;
299 0 : mbInDropDown = sal_False;
300 0 : }
301 :
302 : // --------------------------------------------------------------------
303 :
304 0 : void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
305 : {
306 0 : Edit::ImplInit( pParent, nWinStyle );
307 :
308 0 : if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
309 : {
310 0 : mbSpin = sal_True;
311 :
312 : // Some themes want external spin buttons, therefore the main
313 : // spinfield should not overdraw the border between its encapsulated
314 : // edit field and the spin buttons
315 0 : if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
316 : {
317 0 : SetBackground();
318 0 : mpEdit = new Edit( this, WB_NOBORDER );
319 0 : mpEdit->SetBackground();
320 : }
321 : else
322 0 : mpEdit = new Edit( this, WB_NOBORDER );
323 :
324 0 : mpEdit->EnableRTL( sal_False );
325 0 : mpEdit->SetPosPixel( Point() );
326 0 : mpEdit->Show();
327 0 : SetSubEdit( mpEdit );
328 :
329 0 : maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
330 0 : maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
331 0 : if ( nWinStyle & WB_REPEAT )
332 0 : mbRepeat = sal_True;
333 :
334 0 : SetCompoundControl( sal_True );
335 : }
336 0 : }
337 :
338 : // --------------------------------------------------------------------
339 :
340 0 : SpinField::SpinField( WindowType nTyp ) :
341 0 : Edit( nTyp )
342 : {
343 0 : ImplInitSpinFieldData();
344 0 : }
345 :
346 : // --------------------------------------------------------------------
347 :
348 0 : SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
349 0 : Edit( WINDOW_SPINFIELD )
350 : {
351 0 : ImplInitSpinFieldData();
352 0 : ImplInit( pParent, nWinStyle );
353 0 : }
354 :
355 0 : SpinField::SpinField( Window* pParent, const ResId& rResId ) :
356 0 : Edit( WINDOW_SPINFIELD )
357 : {
358 0 : ImplInitSpinFieldData();
359 0 : rResId.SetRT( RSC_SPINFIELD );
360 0 : WinBits nStyle = ImplInitRes( rResId );
361 0 : ImplInit( pParent, nStyle );
362 0 : ImplLoadRes( rResId );
363 :
364 0 : if ( !(nStyle & WB_HIDE) )
365 0 : Show();
366 0 : }
367 :
368 : // --------------------------------------------------------------------
369 :
370 0 : SpinField::~SpinField()
371 : {
372 0 : delete mpEdit;
373 0 : }
374 :
375 : // --------------------------------------------------------------------
376 :
377 0 : void SpinField::Up()
378 : {
379 0 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
380 0 : }
381 :
382 : // --------------------------------------------------------------------
383 :
384 0 : void SpinField::Down()
385 : {
386 0 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
387 0 : }
388 :
389 : // --------------------------------------------------------------------
390 :
391 0 : void SpinField::First()
392 : {
393 0 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
394 0 : }
395 :
396 : // --------------------------------------------------------------------
397 :
398 0 : void SpinField::Last()
399 : {
400 0 : ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
401 0 : }
402 :
403 : // --------------------------------------------------------------------
404 :
405 0 : void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
406 : {
407 0 : if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
408 : {
409 0 : mbNoSelect = sal_True;
410 0 : GrabFocus();
411 : }
412 :
413 0 : if ( !IsReadOnly() )
414 : {
415 0 : if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
416 : {
417 0 : mbUpperIn = sal_True;
418 0 : mbInitialUp = sal_True;
419 0 : Invalidate( maUpperRect );
420 : }
421 0 : else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
422 : {
423 0 : mbLowerIn = sal_True;
424 0 : mbInitialDown = sal_True;
425 0 : Invalidate( maLowerRect );
426 : }
427 0 : else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
428 : {
429 : // Rechts daneben liegt der DropDownButton:
430 0 : mbInDropDown = ShowDropDown( mbInDropDown ? sal_False : sal_True );
431 0 : Paint( Rectangle( Point(), GetOutputSizePixel() ) );
432 : }
433 :
434 0 : if ( mbUpperIn || mbLowerIn )
435 : {
436 0 : Update();
437 0 : CaptureMouse();
438 0 : if ( mbRepeat )
439 0 : maRepeatTimer.Start();
440 0 : return;
441 : }
442 : }
443 :
444 0 : Edit::MouseButtonDown( rMEvt );
445 : }
446 :
447 : // --------------------------------------------------------------------
448 :
449 0 : void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
450 : {
451 0 : ReleaseMouse();
452 0 : mbInitialUp = mbInitialDown = sal_False;
453 0 : maRepeatTimer.Stop();
454 0 : maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
455 :
456 0 : if ( mbUpperIn )
457 : {
458 0 : mbUpperIn = sal_False;
459 0 : Invalidate( maUpperRect );
460 0 : Update();
461 0 : Up();
462 : }
463 0 : else if ( mbLowerIn )
464 : {
465 0 : mbLowerIn = sal_False;
466 0 : Invalidate( maLowerRect );
467 0 : Update();
468 0 : Down();
469 : }
470 :
471 0 : Edit::MouseButtonUp( rMEvt );
472 0 : }
473 :
474 : // --------------------------------------------------------------------
475 :
476 0 : void SpinField::MouseMove( const MouseEvent& rMEvt )
477 : {
478 0 : if ( rMEvt.IsLeft() )
479 : {
480 0 : if ( mbInitialUp )
481 : {
482 0 : sal_Bool bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
483 0 : if ( bNewUpperIn != mbUpperIn )
484 : {
485 0 : if ( bNewUpperIn )
486 : {
487 0 : if ( mbRepeat )
488 0 : maRepeatTimer.Start();
489 : }
490 : else
491 0 : maRepeatTimer.Stop();
492 :
493 0 : mbUpperIn = bNewUpperIn;
494 0 : Invalidate( maUpperRect );
495 0 : Update();
496 : }
497 : }
498 0 : else if ( mbInitialDown )
499 : {
500 0 : sal_Bool bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
501 0 : if ( bNewLowerIn != mbLowerIn )
502 : {
503 0 : if ( bNewLowerIn )
504 : {
505 0 : if ( mbRepeat )
506 0 : maRepeatTimer.Start();
507 : }
508 : else
509 0 : maRepeatTimer.Stop();
510 :
511 0 : mbLowerIn = bNewLowerIn;
512 0 : Invalidate( maLowerRect );
513 0 : Update();
514 : }
515 : }
516 : }
517 :
518 0 : Edit::MouseMove( rMEvt );
519 0 : }
520 :
521 : // --------------------------------------------------------------------
522 :
523 0 : long SpinField::Notify( NotifyEvent& rNEvt )
524 : {
525 0 : long nDone = 0;
526 0 : if( rNEvt.GetType() == EVENT_KEYINPUT )
527 : {
528 0 : const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
529 0 : if ( !IsReadOnly() )
530 : {
531 0 : sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
532 0 : switch ( rKEvt.GetKeyCode().GetCode() )
533 : {
534 : case KEY_UP:
535 : {
536 0 : if ( !nMod )
537 : {
538 0 : Up();
539 0 : nDone = 1;
540 : }
541 : }
542 0 : break;
543 : case KEY_DOWN:
544 : {
545 0 : if ( !nMod )
546 : {
547 0 : Down();
548 0 : nDone = 1;
549 : }
550 0 : else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
551 : {
552 0 : mbInDropDown = ShowDropDown( sal_True );
553 0 : Paint( Rectangle( Point(), GetOutputSizePixel() ) );
554 0 : nDone = 1;
555 : }
556 : }
557 0 : break;
558 : case KEY_PAGEUP:
559 : {
560 0 : if ( !nMod )
561 : {
562 0 : Last();
563 0 : nDone = 1;
564 : }
565 : }
566 0 : break;
567 : case KEY_PAGEDOWN:
568 : {
569 0 : if ( !nMod )
570 : {
571 0 : First();
572 0 : nDone = 1;
573 : }
574 : }
575 0 : break;
576 : }
577 : }
578 : }
579 :
580 0 : if ( rNEvt.GetType() == EVENT_COMMAND )
581 : {
582 0 : if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
583 : {
584 0 : sal_uInt16 nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
585 0 : if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
586 : || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
587 0 : && HasChildPathFocus()
588 : )
589 : )
590 : {
591 0 : const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
592 0 : if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
593 : {
594 0 : if ( pData->GetDelta() < 0L )
595 0 : Down();
596 : else
597 0 : Up();
598 0 : nDone = 1;
599 : }
600 : }
601 : else
602 0 : nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
603 : }
604 : }
605 :
606 0 : return nDone ? nDone : Edit::Notify( rNEvt );
607 : }
608 :
609 : // --------------------------------------------------------------------
610 :
611 0 : void SpinField::Command( const CommandEvent& rCEvt )
612 : {
613 0 : Edit::Command( rCEvt );
614 0 : }
615 :
616 : // --------------------------------------------------------------------
617 :
618 0 : void SpinField::FillLayoutData() const
619 : {
620 0 : if( mbSpin )
621 : {
622 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
623 0 : AppendLayoutData( *GetSubEdit() );
624 0 : GetSubEdit()->SetLayoutDataParent( this );
625 : }
626 : else
627 0 : Edit::FillLayoutData();
628 0 : }
629 :
630 : // --------------------------------------------------------------------
631 :
632 0 : void SpinField::Paint( const Rectangle& rRect )
633 : {
634 0 : if ( mbSpin )
635 : {
636 0 : sal_Bool bEnable = IsEnabled();
637 : ImplDrawSpinButton( this, maUpperRect, maLowerRect,
638 0 : mbUpperIn, mbLowerIn, bEnable, bEnable );
639 : }
640 :
641 0 : if ( GetStyle() & WB_DROPDOWN )
642 : {
643 0 : DecorationView aView( this );
644 :
645 0 : sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
646 0 : if ( mbInDropDown )
647 0 : nStyle |= BUTTON_DRAW_PRESSED;
648 0 : Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
649 :
650 0 : SymbolType eSymbol = SYMBOL_SPIN_DOWN;
651 0 : if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
652 0 : eSymbol = SYMBOL_SPIN_UPDOWN;
653 :
654 0 : nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
655 0 : aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
656 : }
657 :
658 0 : Edit::Paint( rRect );
659 0 : }
660 :
661 : // --------------------------------------------------------------------
662 :
663 0 : void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
664 : {
665 0 : const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
666 :
667 0 : Size aSize = rOutSz;
668 0 : Size aDropDownSize;
669 :
670 0 : if ( GetStyle() & WB_DROPDOWN )
671 : {
672 0 : long nW = rStyleSettings.GetScrollBarSize();
673 0 : nW = GetDrawPixel( pDev, nW );
674 0 : aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
675 0 : aSize.Width() -= aDropDownSize.Width();
676 0 : rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
677 0 : rDDArea.Top()--;
678 : }
679 : else
680 0 : rDDArea.SetEmpty();
681 :
682 : // Je nach Hoehe, die groessen Berechnen
683 0 : if ( GetStyle() & WB_SPIN )
684 : {
685 0 : long nBottom1 = aSize.Height()/2;
686 0 : long nBottom2 = aSize.Height()-1;
687 0 : long nTop2 = nBottom1;
688 0 : long nTop1 = 0;
689 0 : if ( !(aSize.Height() & 0x01) )
690 0 : nBottom1--;
691 :
692 0 : sal_Bool bNativeRegionOK = sal_False;
693 0 : Rectangle aContentUp, aContentDown;
694 :
695 0 : if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
696 : // there is just no useful native support for spinfields with dropdown
697 0 : ! (GetStyle() & WB_DROPDOWN) &&
698 0 : IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
699 : {
700 0 : Window *pWin = (Window*) pDev;
701 0 : Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
702 :
703 : // get the system's spin button size
704 0 : ImplControlValue aControlValue;
705 0 : Rectangle aBound;
706 0 : Point aPoint;
707 :
708 : // use the full extent of the control
709 0 : Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
710 :
711 : bNativeRegionOK =
712 : pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
713 0 : aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) &&
714 : pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
715 0 : aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown);
716 :
717 0 : if( bNativeRegionOK )
718 : {
719 : // convert back from border space to local coordinates
720 0 : aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
721 0 : aContentUp.Move(-aPoint.X(), -aPoint.Y());
722 0 : aContentDown.Move(-aPoint.X(), -aPoint.Y());
723 0 : }
724 : }
725 :
726 0 : if( bNativeRegionOK )
727 : {
728 0 : rSpinUpArea = aContentUp;
729 0 : rSpinDownArea = aContentDown;
730 : }
731 : else
732 : {
733 0 : aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
734 :
735 0 : rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
736 0 : rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
737 : }
738 : }
739 : else
740 : {
741 0 : rSpinUpArea.SetEmpty();
742 0 : rSpinDownArea.SetEmpty();
743 : }
744 0 : }
745 :
746 : // --------------------------------------------------------------------
747 :
748 0 : void SpinField::Resize()
749 : {
750 0 : if ( mbSpin )
751 : {
752 0 : Control::Resize();
753 0 : Size aSize = GetOutputSizePixel();
754 0 : bool bSubEditPositioned = false;
755 :
756 0 : if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
757 : {
758 0 : ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
759 :
760 0 : ImplControlValue aControlValue;
761 0 : Point aPoint;
762 0 : Rectangle aContent, aBound;
763 :
764 : // use the full extent of the control
765 0 : Window *pBorder = GetWindow( WINDOW_BORDER );
766 0 : Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
767 :
768 : // adjust position and size of the edit field
769 0 : if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
770 0 : aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
771 : {
772 : // convert back from border space to local coordinates
773 0 : aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
774 0 : aContent.Move(-aPoint.X(), -aPoint.Y());
775 :
776 : // use the themes drop down size
777 0 : mpEdit->SetPosPixel( aContent.TopLeft() );
778 0 : bSubEditPositioned = true;
779 0 : aSize = aContent.GetSize();
780 : }
781 : else
782 : {
783 0 : if ( maUpperRect.IsEmpty() )
784 : {
785 : DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
786 0 : aSize.Width() = maDropDownRect.Left();
787 : }
788 : else
789 0 : aSize.Width() = maUpperRect.Left();
790 0 : }
791 : }
792 :
793 0 : if( ! bSubEditPositioned )
794 : {
795 : // this moves our sub edit if RTL gets switched
796 0 : mpEdit->SetPosPixel( Point() );
797 : }
798 0 : mpEdit->SetSizePixel( aSize );
799 :
800 0 : if ( GetStyle() & WB_SPIN )
801 0 : Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
802 0 : if ( GetStyle() & WB_DROPDOWN )
803 0 : Invalidate( maDropDownRect );
804 : }
805 0 : }
806 :
807 : // -----------------------------------------------------------------------
808 :
809 0 : void SpinField::StateChanged( StateChangedType nType )
810 : {
811 0 : Edit::StateChanged( nType );
812 :
813 0 : if ( nType == STATE_CHANGE_ENABLE )
814 : {
815 0 : if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
816 : {
817 0 : mpEdit->Enable( IsEnabled() );
818 :
819 0 : if ( mbSpin )
820 : {
821 0 : Invalidate( maLowerRect );
822 0 : Invalidate( maUpperRect );
823 : }
824 0 : if ( GetStyle() & WB_DROPDOWN )
825 0 : Invalidate( maDropDownRect );
826 : }
827 : }
828 0 : else if ( nType == STATE_CHANGE_STYLE )
829 : {
830 0 : if ( GetStyle() & WB_REPEAT )
831 0 : mbRepeat = sal_True;
832 : else
833 0 : mbRepeat = sal_False;
834 : }
835 0 : else if ( nType == STATE_CHANGE_ZOOM )
836 : {
837 0 : Resize();
838 0 : if ( mpEdit )
839 0 : mpEdit->SetZoom( GetZoom() );
840 0 : Invalidate();
841 : }
842 0 : else if ( nType == STATE_CHANGE_CONTROLFONT )
843 : {
844 0 : if ( mpEdit )
845 0 : mpEdit->SetControlFont( GetControlFont() );
846 0 : ImplInitSettings( sal_True, sal_False, sal_False );
847 0 : Invalidate();
848 : }
849 0 : else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
850 : {
851 0 : if ( mpEdit )
852 0 : mpEdit->SetControlForeground( GetControlForeground() );
853 0 : ImplInitSettings( sal_False, sal_True, sal_False );
854 0 : Invalidate();
855 : }
856 0 : else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
857 : {
858 0 : if ( mpEdit )
859 0 : mpEdit->SetControlBackground( GetControlBackground() );
860 0 : ImplInitSettings( sal_False, sal_False, sal_True );
861 0 : Invalidate();
862 : }
863 0 : else if( nType == STATE_CHANGE_MIRRORING )
864 : {
865 0 : if( mpEdit )
866 0 : mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
867 0 : Resize();
868 : }
869 0 : }
870 :
871 : // -----------------------------------------------------------------------
872 :
873 0 : void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
874 : {
875 0 : Edit::DataChanged( rDCEvt );
876 :
877 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
878 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE) )
879 : {
880 0 : Resize();
881 0 : Invalidate();
882 : }
883 0 : }
884 :
885 : // -----------------------------------------------------------------------
886 :
887 0 : Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
888 : {
889 0 : if( maUpperRect.IsInside( rPt ) )
890 0 : return &maUpperRect;
891 0 : else if( maLowerRect.IsInside( rPt ) )
892 0 : return &maLowerRect;
893 : else
894 0 : return NULL;
895 : }
896 :
897 0 : long SpinField::PreNotify( NotifyEvent& rNEvt )
898 : {
899 0 : long nDone = 0;
900 0 : const MouseEvent* pMouseEvt = NULL;
901 :
902 0 : if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
903 : {
904 0 : if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
905 : {
906 : // trigger redraw if mouse over state has changed
907 0 : if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
908 0 : IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
909 : {
910 0 : Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
911 0 : Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
912 0 : if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
913 : {
914 : // FIXME: this is currently only on aqua
915 : // check for other platforms that need similar handling
916 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
917 0 : IsNativeWidgetEnabled() &&
918 0 : IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
919 : {
920 0 : ImplInvalidateOutermostBorder( this );
921 : }
922 : else
923 : {
924 : // paint directly
925 0 : Region aRgn( GetActiveClipRegion() );
926 0 : if( pLastRect )
927 : {
928 0 : SetClipRegion( *pLastRect );
929 0 : Paint( *pLastRect );
930 0 : SetClipRegion( aRgn );
931 : }
932 0 : if( pRect )
933 : {
934 0 : SetClipRegion( *pRect );
935 0 : Paint( *pRect );
936 0 : SetClipRegion( aRgn );
937 0 : }
938 : }
939 : }
940 : }
941 : }
942 : }
943 :
944 0 : return nDone ? nDone : Edit::PreNotify(rNEvt);
945 : }
946 :
947 : // -----------------------------------------------------------------------
948 :
949 0 : void SpinField::EndDropDown()
950 : {
951 0 : mbInDropDown = sal_False;
952 0 : Paint( Rectangle( Point(), GetOutputSizePixel() ) );
953 0 : }
954 :
955 : // -----------------------------------------------------------------------
956 :
957 0 : sal_Bool SpinField::ShowDropDown( sal_Bool )
958 : {
959 0 : return sal_False;
960 : }
961 :
962 0 : Size SpinField::CalcMinimumSizeForText(const rtl::OUString &rString) const
963 : {
964 0 : Size aSz = Edit::CalcMinimumSizeForText(rString);
965 :
966 0 : if ( GetStyle() & WB_DROPDOWN )
967 0 : aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
968 0 : if ( GetStyle() & WB_SPIN )
969 : {
970 0 : ImplControlValue aControlValue;
971 0 : Rectangle aArea( Point(), Size(100, aSz.Height()));
972 0 : Rectangle aEntireBound, aEntireContent, aEditBound, aEditContent;
973 0 : if (
974 : GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
975 0 : aArea, 0, aControlValue, rtl::OUString(), aEntireBound, aEntireContent) &&
976 : GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
977 0 : aArea, 0, aControlValue, rtl::OUString(), aEditBound, aEditContent)
978 : )
979 : {
980 0 : aSz.Width() += (aEntireContent.GetWidth() - aEditContent.GetWidth());
981 : }
982 : else
983 : {
984 0 : aSz.Width() += maUpperRect.GetWidth();
985 0 : }
986 : }
987 :
988 0 : return aSz;
989 : }
990 :
991 0 : Size SpinField::CalcMinimumSize() const
992 : {
993 0 : return CalcMinimumSizeForText(GetText());
994 : }
995 :
996 : // -----------------------------------------------------------------------
997 :
998 0 : Size SpinField::GetOptimalSize(WindowSizeType eType) const
999 : {
1000 0 : switch (eType) {
1001 : case WINDOWSIZE_MINIMUM:
1002 0 : return CalcMinimumSize();
1003 : default:
1004 0 : return Edit::GetOptimalSize( eType );
1005 : }
1006 : }
1007 :
1008 : // -----------------------------------------------------------------------
1009 :
1010 0 : Size SpinField::CalcSize( sal_uInt16 nChars ) const
1011 : {
1012 0 : Size aSz = Edit::CalcSize( nChars );
1013 :
1014 0 : if ( GetStyle() & WB_DROPDOWN )
1015 0 : aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1016 0 : if ( GetStyle() & WB_SPIN )
1017 0 : aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
1018 :
1019 0 : return aSz;
1020 : }
1021 :
1022 : // --------------------------------------------------------------------
1023 :
1024 0 : IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
1025 : {
1026 0 : if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
1027 : {
1028 0 : pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
1029 0 : pTimer->Start();
1030 : }
1031 : else
1032 : {
1033 0 : if ( mbInitialUp )
1034 0 : Up();
1035 : else
1036 0 : Down();
1037 : }
1038 0 : return 0;
1039 : }
1040 :
1041 : // -----------------------------------------------------------------------
1042 :
1043 0 : void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
1044 : {
1045 0 : Edit::Draw( pDev, rPos, rSize, nFlags );
1046 :
1047 0 : WinBits nFieldStyle = GetStyle();
1048 0 : if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
1049 : {
1050 0 : Point aPos = pDev->LogicToPixel( rPos );
1051 0 : Size aSize = pDev->LogicToPixel( rSize );
1052 0 : OutDevType eOutDevType = pDev->GetOutDevType();
1053 0 : AllSettings aOldSettings = pDev->GetSettings();
1054 :
1055 0 : pDev->Push();
1056 0 : pDev->SetMapMode();
1057 :
1058 0 : if ( eOutDevType == OUTDEV_PRINTER )
1059 : {
1060 0 : StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
1061 0 : aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
1062 0 : aStyleSettings.SetButtonTextColor( COL_BLACK );
1063 0 : AllSettings aSettings( aOldSettings );
1064 0 : aSettings.SetStyleSettings( aStyleSettings );
1065 0 : pDev->SetSettings( aSettings );
1066 : }
1067 :
1068 0 : Rectangle aDD, aUp, aDown;
1069 0 : ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
1070 0 : aDD.Move( aPos.X(), aPos.Y() );
1071 0 : aUp.Move( aPos.X(), aPos.Y() );
1072 0 : aUp.Top()++;
1073 0 : aDown.Move( aPos.X(), aPos.Y() );
1074 :
1075 0 : Color aButtonTextColor;
1076 0 : if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1077 0 : aButtonTextColor = Color( COL_BLACK );
1078 : else
1079 0 : aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
1080 :
1081 0 : if ( GetStyle() & WB_DROPDOWN )
1082 : {
1083 0 : DecorationView aView( pDev );
1084 0 : sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
1085 0 : Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
1086 0 : SymbolType eSymbol = SYMBOL_SPIN_DOWN;
1087 0 : if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
1088 0 : eSymbol = SYMBOL_SPIN_UPDOWN;
1089 :
1090 0 : nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
1091 0 : aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
1092 : }
1093 :
1094 0 : if ( GetStyle() & WB_SPIN )
1095 : {
1096 0 : ImplDrawSpinButton( pDev, aUp, aDown, sal_False, sal_False, sal_True, sal_True );
1097 : }
1098 :
1099 0 : pDev->Pop();
1100 0 : pDev->SetSettings( aOldSettings );
1101 : }
1102 0 : }
1103 :
1104 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|