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