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