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