1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dialcontrol.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include "dialcontrol.hxx"
36 #include <vcl/virdev.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/bitmap.hxx>
39 #include <vcl/field.hxx>
40 #include <svtools/colorcfg.hxx>
44 // ============================================================================
46 const long DIAL_OUTER_WIDTH
= 8;
48 // ============================================================================
50 class DialControlBmp
: public VirtualDevice
53 explicit DialControlBmp( Window
& rParent
);
55 void InitBitmap( const Size
& rSize
, const Font
& rFont
);
56 void CopyBackground( const DialControlBmp
& rSrc
);
57 void DrawBackground( const Size
& rSize
, bool bEnabled
);
58 void DrawElements( const String
& rText
, sal_Int32 nAngle
);
61 const Color
& GetBackgroundColor() const;
62 const Color
& GetTextColor() const;
63 const Color
& GetScaleLineColor() const;
64 const Color
& GetButtonLineColor() const;
65 const Color
& GetButtonFillColor( bool bMain
) const;
67 void Init( const Size
& rSize
);
68 void DrawBackground();
77 // ----------------------------------------------------------------------------
79 DialControlBmp::DialControlBmp( Window
& rParent
) :
80 VirtualDevice( rParent
, 0, 0 ),
87 void DialControlBmp::InitBitmap( const Size
& rSize
, const Font
& rFont
)
93 void DialControlBmp::CopyBackground( const DialControlBmp
& rSrc
)
95 Init( rSrc
.maRect
.GetSize() );
96 mbEnabled
= rSrc
.mbEnabled
;
98 DrawBitmapEx( aPos
, rSrc
.GetBitmapEx( aPos
, maRect
.GetSize() ) );
101 void DialControlBmp::DrawBackground( const Size
& rSize
, bool bEnabled
)
104 mbEnabled
= bEnabled
;
108 void DialControlBmp::DrawElements( const String
& rText
, sal_Int32 nAngle
)
110 // *** rotated text ***
112 Font
aFont( GetFont() );
113 aFont
.SetColor( GetTextColor() );
114 aFont
.SetOrientation( static_cast< short >( (nAngle
+ 5) / 10 ) ); // Font uses 1/10 degrees
115 aFont
.SetWeight( WEIGHT_BOLD
);
118 double fAngle
= nAngle
* F_PI180
/ 100.0;
119 double fSin
= sin( fAngle
);
120 double fCos
= cos( fAngle
);
121 double fWidth
= GetTextWidth( rText
) / 2.0;
122 double fHeight
= GetTextHeight() / 2.0;
123 long nX
= static_cast< long >( mnCenterX
- fWidth
* fCos
- fHeight
* fSin
);
124 long nY
= static_cast< long >( mnCenterY
+ fWidth
* fSin
- fHeight
* fCos
);
125 Rectangle
aRect( nX
, nY
, 2 * mnCenterX
- nX
, 2 * mnCenterY
- nY
);
126 DrawText( aRect
, rText
, mbEnabled
? 0 : TEXT_DRAW_DISABLE
);
128 // *** drag button ***
130 bool bMain
= (nAngle
% 4500) != 0;
131 SetLineColor( GetButtonLineColor() );
132 SetFillColor( GetButtonFillColor( bMain
) );
134 nX
= mnCenterX
- static_cast< long >( (DIAL_OUTER_WIDTH
/ 2 - mnCenterX
) * fCos
);
135 nY
= mnCenterY
- static_cast< long >( (mnCenterY
- DIAL_OUTER_WIDTH
/ 2) * fSin
);
136 long nSize
= bMain
? (DIAL_OUTER_WIDTH
/ 4) : (DIAL_OUTER_WIDTH
/ 2 - 1);
137 DrawEllipse( Rectangle( nX
- nSize
, nY
- nSize
, nX
+ nSize
, nY
+ nSize
) );
140 // private --------------------------------------------------------------------
142 const Color
& DialControlBmp::GetBackgroundColor() const
144 return GetSettings().GetStyleSettings().GetDialogColor();
147 const Color
& DialControlBmp::GetTextColor() const
149 return GetSettings().GetStyleSettings().GetLabelTextColor();
152 const Color
& DialControlBmp::GetScaleLineColor() const
154 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
155 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
158 const Color
& DialControlBmp::GetButtonLineColor() const
160 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
161 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
164 const Color
& DialControlBmp::GetButtonFillColor( bool bMain
) const
166 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
167 return mbEnabled
? (bMain
? rSett
.GetMenuColor() : rSett
.GetHighlightColor()) : rSett
.GetDisableColor();
170 void DialControlBmp::Init( const Size
& rSize
)
172 SetSettings( mrParent
.GetSettings() );
173 maRect
.SetPos( Point( 0, 0 ) );
174 maRect
.SetSize( rSize
);
175 mnCenterX
= rSize
.Width() / 2;
176 mnCenterY
= rSize
.Height() / 2;
177 SetOutputSize( rSize
);
181 void DialControlBmp::DrawBackground()
183 // *** background with 3D effect ***
189 EnableRTL( TRUE
); // #107807# draw 3D effect in correct direction
191 sal_uInt8 nDiff
= mbEnabled
? 0x18 : 0x10;
194 aColor
= GetBackgroundColor();
195 SetFillColor( aColor
);
196 DrawPie( maRect
, maRect
.TopRight(), maRect
.TopCenter() );
197 DrawPie( maRect
, maRect
.BottomLeft(), maRect
.BottomCenter() );
199 aColor
.DecreaseLuminance( nDiff
);
200 SetFillColor( aColor
);
201 DrawPie( maRect
, maRect
.BottomCenter(), maRect
.TopRight() );
203 aColor
.DecreaseLuminance( nDiff
);
204 SetFillColor( aColor
);
205 DrawPie( maRect
, maRect
.BottomRight(), maRect
.RightCenter() );
207 aColor
= GetBackgroundColor();
208 aColor
.IncreaseLuminance( nDiff
);
209 SetFillColor( aColor
);
210 DrawPie( maRect
, maRect
.TopCenter(), maRect
.BottomLeft() );
212 aColor
.IncreaseLuminance( nDiff
);
213 SetFillColor( aColor
);
214 DrawPie( maRect
, maRect
.TopLeft(), maRect
.LeftCenter() );
218 // *** calibration ***
220 Point
aStartPos( mnCenterX
, mnCenterY
);
221 Color
aFullColor( GetScaleLineColor() );
222 Color
aLightColor( GetBackgroundColor() );
223 aLightColor
.Merge( aFullColor
, 128 );
225 for( int nAngle
= 0; nAngle
< 360; nAngle
+= 15 )
227 SetLineColor( (nAngle
% 45) ? aLightColor
: aFullColor
);
228 double fAngle
= nAngle
* F_PI180
;
229 long nX
= static_cast< long >( -mnCenterX
* cos( fAngle
) );
230 long nY
= static_cast< long >( mnCenterY
* sin( fAngle
) );
231 DrawLine( aStartPos
, Point( mnCenterX
- nX
, mnCenterY
- nY
) );
234 // *** clear inner area ***
237 SetFillColor( GetBackgroundColor() );
238 DrawEllipse( Rectangle( maRect
.Left() + DIAL_OUTER_WIDTH
, maRect
.Top() + DIAL_OUTER_WIDTH
,
239 maRect
.Right() - DIAL_OUTER_WIDTH
, maRect
.Bottom() - DIAL_OUTER_WIDTH
) );
242 // ============================================================================
244 struct DialControl_Impl
246 DialControlBmp maBmpEnabled
;
247 DialControlBmp maBmpDisabled
;
248 DialControlBmp maBmpBuffered
;
250 NumericField
* mpLinkField
;
254 sal_Int32 mnOldAngle
;
259 explicit DialControl_Impl( Window
& rParent
);
260 void Init( const Size
& rWinSize
, const Font
& rWinFont
);
263 // ----------------------------------------------------------------------------
265 DialControl_Impl::DialControl_Impl( Window
& rParent
) :
266 maBmpEnabled( rParent
),
267 maBmpDisabled( rParent
),
268 maBmpBuffered( rParent
),
275 void DialControl_Impl::Init( const Size
& rWinSize
, const Font
& rWinFont
)
277 // "(x - 1) | 1" creates odd value <= x, to have a well-defined center pixel position
278 maWinSize
= Size( (rWinSize
.Width() - 1) | 1, (rWinSize
.Height() - 1) | 1 );
279 maWinFont
= rWinFont
;
281 mnCenterX
= maWinSize
.Width() / 2;
282 mnCenterY
= maWinSize
.Height() / 2;
283 maWinFont
.SetTransparent( TRUE
);
285 maBmpEnabled
.DrawBackground( maWinSize
, true );
286 maBmpDisabled
.DrawBackground( maWinSize
, false );
287 maBmpBuffered
.InitBitmap( maWinSize
, maWinFont
);
290 // ============================================================================
292 DialControl::DialControl( Window
* pParent
, const Size
& rSize
, const Font
& rFont
, WinBits nWinStyle
) :
293 Control( pParent
, nWinStyle
),
294 mpImpl( new DialControl_Impl( *this ) )
296 Init( rSize
, rFont
);
299 DialControl::DialControl( Window
* pParent
, const Size
& rSize
, WinBits nWinStyle
) :
300 Control( pParent
, nWinStyle
),
301 mpImpl( new DialControl_Impl( *this ) )
304 Init( rSize
, pParent
->GetFont() );
309 DialControl::DialControl( Window
* pParent
, const ResId
& rResId
) :
310 Control( pParent
, rResId
),
311 mpImpl( new DialControl_Impl( *this ) )
313 Init( GetOutputSizePixel() );
316 DialControl::~DialControl()
320 void DialControl::Paint( const Rectangle
& )
323 DrawBitmapEx( aPos
, mpImpl
->maBmpBuffered
.GetBitmapEx( aPos
, mpImpl
->maWinSize
) );
326 void DialControl::StateChanged( StateChangedType nStateChange
)
328 if( nStateChange
== STATE_CHANGE_ENABLE
)
331 // update the linked edit field
332 if( mpImpl
->mpLinkField
)
334 NumericField
& rField
= *mpImpl
->mpLinkField
;
335 switch( nStateChange
)
337 case STATE_CHANGE_VISIBLE
: rField
.Show( IsVisible() ); break;
338 case STATE_CHANGE_ENABLE
: rField
.Enable( IsEnabled() ); break;
342 Control::StateChanged( nStateChange
);
345 void DialControl::DataChanged( const DataChangedEvent
& rDCEvt
)
347 if( (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) && (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
349 Init( mpImpl
->maWinSize
, mpImpl
->maWinFont
);
352 Control::DataChanged( rDCEvt
);
355 void DialControl::MouseButtonDown( const MouseEvent
& rMEvt
)
361 mpImpl
->mnOldAngle
= mpImpl
->mnAngle
;
362 HandleMouseEvent( rMEvt
.GetPosPixel(), true );
364 Control::MouseButtonDown( rMEvt
);
367 void DialControl::MouseMove( const MouseEvent
& rMEvt
)
369 if( IsMouseCaptured() && rMEvt
.IsLeft() )
370 HandleMouseEvent( rMEvt
.GetPosPixel(), false );
371 Control::MouseMove(rMEvt
);
374 void DialControl::MouseButtonUp( const MouseEvent
& rMEvt
)
376 if( IsMouseCaptured() )
379 if( mpImpl
->mpLinkField
)
380 mpImpl
->mpLinkField
->GrabFocus();
382 Control::MouseButtonUp( rMEvt
);
385 void DialControl::KeyInput( const KeyEvent
& rKEvt
)
387 const KeyCode
& rKCode
= rKEvt
.GetKeyCode();
388 if( !rKCode
.GetModifier() && (rKCode
.GetCode() == KEY_ESCAPE
) )
391 Control::KeyInput( rKEvt
);
394 void DialControl::LoseFocus()
396 // release captured mouse
398 Control::LoseFocus();
401 bool DialControl::HasRotation() const
403 return !mpImpl
->mbNoRot
;
406 void DialControl::SetNoRotation()
408 if( !mpImpl
->mbNoRot
)
410 mpImpl
->mbNoRot
= true;
412 if( mpImpl
->mpLinkField
)
413 mpImpl
->mpLinkField
->SetText( String() );
417 sal_Int32
DialControl::GetRotation() const
419 return mpImpl
->mnAngle
;
422 void DialControl::SetRotation( sal_Int32 nAngle
)
424 ImplSetRotation( nAngle
, false );
427 void DialControl::SetLinkedField( NumericField
* pField
)
429 // remove modify handler from old linked field
430 ImplSetFieldLink( Link() );
431 // remember the new linked field
432 mpImpl
->mpLinkField
= pField
;
433 // set modify handler at new linked field
434 ImplSetFieldLink( LINK( this, DialControl
, LinkedFieldModifyHdl
) );
437 NumericField
* DialControl::GetLinkedField() const
439 return mpImpl
->mpLinkField
;
442 void DialControl::SetModifyHdl( const Link
& rLink
)
444 mpImpl
->maModifyHdl
= rLink
;
447 const Link
& DialControl::GetModifyHdl() const
449 return mpImpl
->maModifyHdl
;
452 // private --------------------------------------------------------------------
454 void DialControl::Init( const Size
& rWinSize
, const Font
& rWinFont
)
456 mpImpl
->Init( rWinSize
, rWinFont
);
457 EnableRTL( FALSE
); // #107807# don't mirror mouse handling
458 SetOutputSizePixel( mpImpl
->maWinSize
);
462 void DialControl::Init( const Size
& rWinSize
)
464 Font
aFont( OutputDevice::GetDefaultFont(
465 DEFAULTFONT_UI_SANS
, Application::GetSettings().GetUILanguage(), DEFAULTFONT_FLAGS_ONLYONE
) );
466 Init( rWinSize
, aFont
);
469 void DialControl::InvalidateControl()
471 mpImpl
->maBmpBuffered
.CopyBackground( IsEnabled() ? mpImpl
->maBmpEnabled
: mpImpl
->maBmpDisabled
);
472 if( !mpImpl
->mbNoRot
)
473 mpImpl
->maBmpBuffered
.DrawElements( GetText(), mpImpl
->mnAngle
);
477 void DialControl::ImplSetRotation( sal_Int32 nAngle
, bool bBroadcast
)
479 bool bOldSel
= mpImpl
->mbNoRot
;
480 mpImpl
->mbNoRot
= false;
482 while( nAngle
< 0 ) nAngle
+= 36000;
483 nAngle
= (((nAngle
+ 50) / 100) * 100) % 36000;
484 if( !bOldSel
|| (mpImpl
->mnAngle
!= nAngle
) )
486 mpImpl
->mnAngle
= nAngle
;
488 if( mpImpl
->mpLinkField
)
489 mpImpl
->mpLinkField
->SetValue( static_cast< long >( GetRotation() / 100 ) );
491 mpImpl
->maModifyHdl
.Call( this );
495 void DialControl::ImplSetFieldLink( const Link
& rLink
)
497 if( mpImpl
->mpLinkField
)
499 NumericField
& rField
= *mpImpl
->mpLinkField
;
500 rField
.SetModifyHdl( rLink
);
501 rField
.SetUpHdl( rLink
);
502 rField
.SetDownHdl( rLink
);
503 rField
.SetFirstHdl( rLink
);
504 rField
.SetLastHdl( rLink
);
505 rField
.SetLoseFocusHdl( rLink
);
509 void DialControl::HandleMouseEvent( const Point
& rPos
, bool bInitial
)
511 long nX
= rPos
.X() - mpImpl
->mnCenterX
;
512 long nY
= mpImpl
->mnCenterY
- rPos
.Y();
513 double fH
= sqrt( static_cast< double >( nX
) * nX
+ static_cast< double >( nY
) * nY
);
516 double fAngle
= acos( nX
/ fH
);
517 sal_Int32 nAngle
= static_cast< sal_Int32
>( fAngle
/ F_PI180
* 100.0 );
519 nAngle
= 36000 - nAngle
;
520 if( bInitial
) // round to entire 15 degrees
521 nAngle
= ((nAngle
+ 750) / 1500) * 1500;
522 ImplSetRotation( nAngle
, true );
526 void DialControl::HandleEscapeEvent()
528 if( IsMouseCaptured() )
531 ImplSetRotation( mpImpl
->mnOldAngle
, true );
532 if( mpImpl
->mpLinkField
)
533 mpImpl
->mpLinkField
->GrabFocus();
537 IMPL_LINK( DialControl
, LinkedFieldModifyHdl
, NumericField
*, pField
)
540 ImplSetRotation( static_cast< sal_Int32
>( pField
->GetValue() * 100 ), false );
544 // ============================================================================
546 DialControlWrapper::DialControlWrapper( DialControl
& rDial
) :
547 SingleControlWrapperType( rDial
)
551 bool DialControlWrapper::IsControlDontKnow() const
553 return !GetControl().HasRotation();
556 void DialControlWrapper::SetControlDontKnow( bool bSet
)
559 GetControl().SetNoRotation();
562 sal_Int32
DialControlWrapper::GetControlValue() const
564 return GetControl().GetRotation();
567 void DialControlWrapper::SetControlValue( sal_Int32 nValue
)
569 GetControl().SetRotation( nValue
);
572 // ============================================================================