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