1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "svx/dialcontrol.hxx"
21 #include "bmpmask.hrc"
22 #include <svx/dialmgr.hxx>
23 #include <tools/rcid.h>
25 #include <vcl/virdev.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/bitmap.hxx>
28 #include <vcl/field.hxx>
29 #include <svtools/colorcfg.hxx>
30 #include <vcl/builder.hxx>
34 // ============================================================================
36 const long DIAL_OUTER_WIDTH
= 8;
38 // ----------------------------------------------------------------------------
40 DialControlBmp::DialControlBmp( Window
& rParent
) :
41 VirtualDevice( rParent
, 0, 0 ),
47 EnableRTL( sal_False
);
50 void DialControlBmp::InitBitmap(const Font
& rFont
)
56 void DialControlBmp::CopyBackground( const DialControlBmp
& rSrc
)
59 SetSize(rSrc
.maRect
.GetSize());
60 mbEnabled
= rSrc
.mbEnabled
;
62 DrawBitmapEx( aPos
, rSrc
.GetBitmapEx( aPos
, maRect
.GetSize() ) );
65 void DialControlBmp::DrawBackground( const Size
& rSize
, bool bEnabled
)
73 void DialControlBmp::DrawElements( const String
& rText
, sal_Int32 nAngle
)
75 // *** rotated text ***
77 Font
aFont( GetFont() );
78 aFont
.SetColor( GetTextColor() );
79 aFont
.SetOrientation( static_cast< short >( (nAngle
+ 5) / 10 ) ); // Font uses 1/10 degrees
80 aFont
.SetWeight( WEIGHT_BOLD
);
83 double fAngle
= nAngle
* F_PI180
/ 100.0;
84 double fSin
= sin( fAngle
);
85 double fCos
= cos( fAngle
);
86 double fWidth
= GetTextWidth( rText
) / 2.0;
87 double fHeight
= GetTextHeight() / 2.0;
88 long nX
= static_cast< long >( mnCenterX
- fWidth
* fCos
- fHeight
* fSin
);
89 long nY
= static_cast< long >( mnCenterY
+ fWidth
* fSin
- fHeight
* fCos
);
90 Rectangle
aRect( nX
, nY
, 2 * mnCenterX
- nX
, 2 * mnCenterY
- nY
);
91 DrawText( aRect
, rText
, mbEnabled
? 0 : TEXT_DRAW_DISABLE
);
93 // *** drag button ***
95 bool bMain
= (nAngle
% 4500) != 0;
96 SetLineColor( GetButtonLineColor() );
97 SetFillColor( GetButtonFillColor( bMain
) );
99 nX
= mnCenterX
- static_cast< long >( (DIAL_OUTER_WIDTH
/ 2 - mnCenterX
) * fCos
);
100 nY
= mnCenterY
- static_cast< long >( (mnCenterY
- DIAL_OUTER_WIDTH
/ 2) * fSin
);
101 long nSize
= bMain
? (DIAL_OUTER_WIDTH
/ 4) : (DIAL_OUTER_WIDTH
/ 2 - 1);
102 DrawEllipse( Rectangle( nX
- nSize
, nY
- nSize
, nX
+ nSize
, nY
+ nSize
) );
105 // private --------------------------------------------------------------------
107 const Color
& DialControlBmp::GetBackgroundColor() const
109 return GetSettings().GetStyleSettings().GetDialogColor();
112 const Color
& DialControlBmp::GetTextColor() const
114 return GetSettings().GetStyleSettings().GetLabelTextColor();
117 const Color
& DialControlBmp::GetScaleLineColor() const
119 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
120 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
123 const Color
& DialControlBmp::GetButtonLineColor() const
125 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
126 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
129 const Color
& DialControlBmp::GetButtonFillColor( bool bMain
) const
131 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
132 return mbEnabled
? (bMain
? rSett
.GetMenuColor() : rSett
.GetHighlightColor()) : rSett
.GetDisableColor();
135 void DialControlBmp::Init()
137 SetSettings(mrParent
.GetSettings());
141 void DialControlBmp::SetSize( const Size
& rSize
)
143 maRect
.SetPos( Point( 0, 0 ) );
144 maRect
.SetSize( rSize
);
145 mnCenterX
= rSize
.Width() / 2;
146 mnCenterY
= rSize
.Height() / 2;
147 SetOutputSize( rSize
);
150 void DialControlBmp::DrawBackground()
152 // *** background with 3D effect ***
158 EnableRTL( sal_True
); // draw 3D effect in correct direction
160 sal_uInt8 nDiff
= mbEnabled
? 0x18 : 0x10;
163 aColor
= GetBackgroundColor();
164 SetFillColor( aColor
);
165 DrawPie( maRect
, maRect
.TopRight(), maRect
.TopCenter() );
166 DrawPie( maRect
, maRect
.BottomLeft(), maRect
.BottomCenter() );
168 aColor
.DecreaseLuminance( nDiff
);
169 SetFillColor( aColor
);
170 DrawPie( maRect
, maRect
.BottomCenter(), maRect
.TopRight() );
172 aColor
.DecreaseLuminance( nDiff
);
173 SetFillColor( aColor
);
174 DrawPie( maRect
, maRect
.BottomRight(), maRect
.RightCenter() );
176 aColor
= GetBackgroundColor();
177 aColor
.IncreaseLuminance( nDiff
);
178 SetFillColor( aColor
);
179 DrawPie( maRect
, maRect
.TopCenter(), maRect
.BottomLeft() );
181 aColor
.IncreaseLuminance( nDiff
);
182 SetFillColor( aColor
);
183 DrawPie( maRect
, maRect
.TopLeft(), maRect
.LeftCenter() );
185 EnableRTL( sal_False
);
187 // *** calibration ***
189 Point
aStartPos( mnCenterX
, mnCenterY
);
190 Color
aFullColor( GetScaleLineColor() );
191 Color
aLightColor( GetBackgroundColor() );
192 aLightColor
.Merge( aFullColor
, 128 );
194 for( int nAngle
= 0; nAngle
< 360; nAngle
+= 15 )
196 SetLineColor( (nAngle
% 45) ? aLightColor
: aFullColor
);
197 double fAngle
= nAngle
* F_PI180
;
198 long nX
= static_cast< long >( -mnCenterX
* cos( fAngle
) );
199 long nY
= static_cast< long >( mnCenterY
* sin( fAngle
) );
200 DrawLine( aStartPos
, Point( mnCenterX
- nX
, mnCenterY
- nY
) );
203 // *** clear inner area ***
206 SetFillColor( GetBackgroundColor() );
207 DrawEllipse( Rectangle( maRect
.Left() + DIAL_OUTER_WIDTH
, maRect
.Top() + DIAL_OUTER_WIDTH
,
208 maRect
.Right() - DIAL_OUTER_WIDTH
, maRect
.Bottom() - DIAL_OUTER_WIDTH
) );
211 // ----------------------------------------------------------------------------
213 DialControl::DialControl_Impl::DialControl_Impl (
215 mpBmpEnabled(new DialControlBmp(rParent
)),
216 mpBmpDisabled(new DialControlBmp(rParent
)),
217 mpBmpBuffered(new DialControlBmp(rParent
)),
227 void DialControl::DialControl_Impl::Init( const Size
& rWinSize
, const Font
& rWinFont
)
229 maWinFont
= rWinFont
;
230 maWinFont
.SetTransparent(true);
231 mpBmpBuffered
->InitBitmap(maWinFont
);
235 void DialControl::DialControl_Impl::SetSize( const Size
& rWinSize
)
237 // "(x - 1) | 1" creates odd value <= x, to have a well-defined center pixel position
238 maWinSize
= Size( (rWinSize
.Width() - 1) | 1, (rWinSize
.Height() - 1) | 1 );
240 mnCenterX
= maWinSize
.Width() / 2;
241 mnCenterY
= maWinSize
.Height() / 2;
243 mpBmpEnabled
->DrawBackground( maWinSize
, true );
244 mpBmpDisabled
->DrawBackground( maWinSize
, false );
245 mpBmpBuffered
->SetSize( maWinSize
);
248 // ============================================================================
250 DialControl::DialControl( Window
* pParent
, const ResId
& rResId
) :
251 Control( pParent
, rResId
),
252 mpImpl( new DialControl_Impl( *this ) )
254 Init( GetOutputSizePixel() );
257 DialControl::DialControl( Window
* pParent
, WinBits nBits
) :
258 Control( pParent
, nBits
),
259 mpImpl( new DialControl_Impl( *this ) )
261 Init( GetOutputSizePixel() );
264 DialControl::~DialControl()
268 extern "C" SAL_DLLPUBLIC_EXPORT Window
* SAL_CALL
makeDialControl(Window
*pParent
, VclBuilder::stringmap
&)
270 return new DialControl(pParent
, WB_TABSTOP
);
273 void DialControl::Resize()
275 mpImpl
->SetSize(GetOutputSizePixel());
279 void DialControl::Paint( const Rectangle
& )
282 DrawBitmapEx( aPos
, mpImpl
->mpBmpBuffered
->GetBitmapEx( aPos
, mpImpl
->maWinSize
) );
285 void DialControl::StateChanged( StateChangedType nStateChange
)
287 if( nStateChange
== STATE_CHANGE_ENABLE
)
290 // update the linked edit field
291 if( mpImpl
->mpLinkField
)
293 NumericField
& rField
= *mpImpl
->mpLinkField
;
294 switch( nStateChange
)
296 case STATE_CHANGE_VISIBLE
: rField
.Show( IsVisible() ); break;
297 case STATE_CHANGE_ENABLE
: rField
.Enable( IsEnabled() ); break;
301 Control::StateChanged( nStateChange
);
304 void DialControl::DataChanged( const DataChangedEvent
& rDCEvt
)
306 if( (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) && (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
308 Init( mpImpl
->maWinSize
, mpImpl
->maWinFont
);
311 Control::DataChanged( rDCEvt
);
314 void DialControl::MouseButtonDown( const MouseEvent
& rMEvt
)
320 mpImpl
->mnOldAngle
= mpImpl
->mnAngle
;
321 HandleMouseEvent( rMEvt
.GetPosPixel(), true );
323 Control::MouseButtonDown( rMEvt
);
326 void DialControl::MouseMove( const MouseEvent
& rMEvt
)
328 if( IsMouseCaptured() && rMEvt
.IsLeft() )
329 HandleMouseEvent( rMEvt
.GetPosPixel(), false );
330 Control::MouseMove(rMEvt
);
333 void DialControl::MouseButtonUp( const MouseEvent
& rMEvt
)
335 if( IsMouseCaptured() )
338 if( mpImpl
->mpLinkField
)
339 mpImpl
->mpLinkField
->GrabFocus();
341 Control::MouseButtonUp( rMEvt
);
344 void DialControl::KeyInput( const KeyEvent
& rKEvt
)
346 const KeyCode
& rKCode
= rKEvt
.GetKeyCode();
347 if( !rKCode
.GetModifier() && (rKCode
.GetCode() == KEY_ESCAPE
) )
350 Control::KeyInput( rKEvt
);
353 void DialControl::LoseFocus()
355 // release captured mouse
357 Control::LoseFocus();
360 bool DialControl::HasRotation() const
362 return !mpImpl
->mbNoRot
;
365 void DialControl::SetNoRotation()
367 if( !mpImpl
->mbNoRot
)
369 mpImpl
->mbNoRot
= true;
371 if( mpImpl
->mpLinkField
)
372 mpImpl
->mpLinkField
->SetText( String() );
376 sal_Int32
DialControl::GetRotation() const
378 return mpImpl
->mnAngle
;
381 Size
DialControl::GetOptimalSize() const
383 return LogicToPixel(Size(42 , 43), MAP_APPFONT
);
386 void DialControl::SetRotation( sal_Int32 nAngle
)
388 SetRotation( nAngle
, false );
391 void DialControl::SetLinkedField( NumericField
* pField
, sal_Int32 nDecimalPlaces
)
393 mpImpl
->mnLinkedFieldValueMultiplyer
= static_cast<sal_Int32
> (100.0 / pow(10.0, nDecimalPlaces
));
395 // remove modify handler from old linked field
396 ImplSetFieldLink( Link() );
397 // remember the new linked field
398 mpImpl
->mpLinkField
= pField
;
399 // set modify handler at new linked field
400 ImplSetFieldLink( LINK( this, DialControl
, LinkedFieldModifyHdl
) );
403 void DialControl::SaveValue()
405 mpImpl
->mnInitialAngle
= mpImpl
->mnAngle
;
408 bool DialControl::IsValueModified()
410 return mpImpl
->mnInitialAngle
!= mpImpl
->mnAngle
;
413 NumericField
* DialControl::GetLinkedField() const
415 return mpImpl
->mpLinkField
;
418 void DialControl::SetModifyHdl( const Link
& rLink
)
420 mpImpl
->maModifyHdl
= rLink
;
423 const Link
& DialControl::GetModifyHdl() const
425 return mpImpl
->maModifyHdl
;
428 // private --------------------------------------------------------------------
430 void DialControl::Init( const Size
& rWinSize
, const Font
& rWinFont
)
432 mpImpl
->Init( rWinSize
, rWinFont
);
433 EnableRTL( sal_False
); // don't mirror mouse handling
434 SetOutputSizePixel( mpImpl
->maWinSize
);
438 void DialControl::Init( const Size
& rWinSize
)
440 Font
aFont( OutputDevice::GetDefaultFont(
441 DEFAULTFONT_UI_SANS
, Application::GetSettings().GetUILanguageTag().getLanguageType(), DEFAULTFONT_FLAGS_ONLYONE
) );
442 Init( rWinSize
, aFont
);
445 void DialControl::InvalidateControl()
447 mpImpl
->mpBmpBuffered
->CopyBackground( IsEnabled() ? *mpImpl
->mpBmpEnabled
: *mpImpl
->mpBmpDisabled
);
448 if( !mpImpl
->mbNoRot
)
449 mpImpl
->mpBmpBuffered
->DrawElements( GetText(), mpImpl
->mnAngle
);
453 void DialControl::SetRotation( sal_Int32 nAngle
, bool bBroadcast
)
455 bool bOldSel
= mpImpl
->mbNoRot
;
456 mpImpl
->mbNoRot
= false;
461 if( !bOldSel
|| (mpImpl
->mnAngle
!= nAngle
) )
463 mpImpl
->mnAngle
= nAngle
;
465 if( mpImpl
->mpLinkField
)
466 mpImpl
->mpLinkField
->SetValue( static_cast< long >( GetRotation() / mpImpl
->mnLinkedFieldValueMultiplyer
) );
468 mpImpl
->maModifyHdl
.Call( this );
472 void DialControl::ImplSetFieldLink( const Link
& rLink
)
474 if( mpImpl
->mpLinkField
)
476 NumericField
& rField
= *mpImpl
->mpLinkField
;
477 rField
.SetModifyHdl( rLink
);
478 rField
.SetUpHdl( rLink
);
479 rField
.SetDownHdl( rLink
);
480 rField
.SetFirstHdl( rLink
);
481 rField
.SetLastHdl( rLink
);
482 rField
.SetLoseFocusHdl( rLink
);
486 void DialControl::HandleMouseEvent( const Point
& rPos
, bool bInitial
)
488 long nX
= rPos
.X() - mpImpl
->mnCenterX
;
489 long nY
= mpImpl
->mnCenterY
- rPos
.Y();
490 double fH
= sqrt( static_cast< double >( nX
) * nX
+ static_cast< double >( nY
) * nY
);
493 double fAngle
= acos( nX
/ fH
);
494 sal_Int32 nAngle
= static_cast< sal_Int32
>( fAngle
/ F_PI180
* 100.0 );
496 nAngle
= 36000 - nAngle
;
497 if( bInitial
) // round to entire 15 degrees
498 nAngle
= ((nAngle
+ 750) / 1500) * 1500;
499 // Round up to 1 degree
500 nAngle
= (((nAngle
+ 50) / 100) * 100) % 36000;
501 SetRotation( nAngle
, true );
505 void DialControl::HandleEscapeEvent()
507 if( IsMouseCaptured() )
510 SetRotation( mpImpl
->mnOldAngle
, true );
511 if( mpImpl
->mpLinkField
)
512 mpImpl
->mpLinkField
->GrabFocus();
516 IMPL_LINK( DialControl
, LinkedFieldModifyHdl
, NumericField
*, pField
)
519 SetRotation( static_cast< sal_Int32
>( pField
->GetValue() * mpImpl
->mnLinkedFieldValueMultiplyer
), false );
523 // ============================================================================
525 DialControlWrapper::DialControlWrapper( DialControl
& rDial
) :
526 SingleControlWrapperType( rDial
)
530 bool DialControlWrapper::IsControlDontKnow() const
532 return !GetControl().HasRotation();
535 void DialControlWrapper::SetControlDontKnow( bool bSet
)
538 GetControl().SetNoRotation();
541 sal_Int32
DialControlWrapper::GetControlValue() const
543 return GetControl().GetRotation();
546 void DialControlWrapper::SetControlValue( sal_Int32 nValue
)
548 GetControl().SetRotation( nValue
);
551 // ============================================================================
555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */