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