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 <vcl/settings.hxx>
30 #include <svtools/colorcfg.hxx>
31 #include <vcl/builderfactory.hxx>
35 const long DIAL_OUTER_WIDTH
= 8;
37 DialControlBmp::DialControlBmp(vcl::Window
& rParent
) :
38 VirtualDevice(rParent
, 0, 0),
47 void DialControlBmp::InitBitmap(const vcl::Font
& rFont
)
53 void DialControlBmp::CopyBackground( const DialControlBmp
& rSrc
)
56 SetSize(rSrc
.maRect
.GetSize());
57 mbEnabled
= rSrc
.mbEnabled
;
59 DrawBitmapEx( aPos
, rSrc
.GetBitmapEx( aPos
, maRect
.GetSize() ) );
62 void DialControlBmp::DrawBackground( const Size
& rSize
, bool bEnabled
)
70 void DialControlBmp::DrawElements( const OUString
& rText
, sal_Int32 nAngle
)
72 double fAngle
= nAngle
* F_PI180
/ 100.0;
73 double fSin
= sin( fAngle
);
74 double fCos
= cos( fAngle
);
75 double fWidth
= GetTextWidth( rText
) / 2.0;
76 double fHeight
= GetTextHeight() / 2.0;
78 if ( !rText
.isEmpty() )
81 vcl::Font
aFont( GetFont() );
82 aFont
.SetColor( GetTextColor() );
83 aFont
.SetOrientation( static_cast< short >( (nAngle
+ 5) / 10 ) ); // Font uses 1/10 degrees
84 aFont
.SetWeight( WEIGHT_BOLD
);
87 long nX
= static_cast< long >( mnCenterX
- fWidth
* fCos
- fHeight
* fSin
);
88 long nY
= static_cast< long >( mnCenterY
+ fWidth
* fSin
- fHeight
* fCos
);
89 Rectangle
aRect( nX
, nY
, 2 * mnCenterX
- nX
, 2 * mnCenterY
- nY
);
90 DrawText( aRect
, rText
, mbEnabled
? DrawTextFlags::NONE
: DrawTextFlags::Disable
);
95 const sal_Int32
nDx (fCos
* (maRect
.GetWidth()-4) / 2);
96 const sal_Int32
nDy (-fSin
* (maRect
.GetHeight()-4) / 2);
97 Point
pt1( maRect
.Center() );
98 Point
pt2( pt1
.X() + nDx
, pt1
.Y() + nDy
);
100 SetLineColor( GetTextColor() );
101 DrawLine( pt1
, pt2
);
104 // *** drag button ***
106 bool bMain
= (nAngle
% 4500) != 0;
107 SetLineColor( GetButtonLineColor() );
108 SetFillColor( GetButtonFillColor( bMain
) );
110 long nX
= mnCenterX
- static_cast< long >( (DIAL_OUTER_WIDTH
/ 2 - mnCenterX
) * fCos
);
111 long nY
= mnCenterY
- static_cast< long >( (mnCenterY
- DIAL_OUTER_WIDTH
/ 2) * fSin
);
112 long nSize
= bMain
? (DIAL_OUTER_WIDTH
/ 4) : (DIAL_OUTER_WIDTH
/ 2 - 1);
113 DrawEllipse( Rectangle( nX
- nSize
, nY
- nSize
, nX
+ nSize
, nY
+ nSize
) );
116 const Color
& DialControlBmp::GetBackgroundColor() const
118 return GetSettings().GetStyleSettings().GetDialogColor();
121 const Color
& DialControlBmp::GetTextColor() const
123 return GetSettings().GetStyleSettings().GetLabelTextColor();
126 const Color
& DialControlBmp::GetScaleLineColor() const
128 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
129 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
132 const Color
& DialControlBmp::GetButtonLineColor() const
134 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
135 return mbEnabled
? rSett
.GetButtonTextColor() : rSett
.GetDisableColor();
138 const Color
& DialControlBmp::GetButtonFillColor( bool bMain
) const
140 const StyleSettings
& rSett
= GetSettings().GetStyleSettings();
141 return mbEnabled
? (bMain
? rSett
.GetMenuColor() : rSett
.GetHighlightColor()) : rSett
.GetDisableColor();
144 void DialControlBmp::Init()
146 SetSettings(mrParent
.GetSettings());
150 void DialControlBmp::SetSize( const Size
& rSize
)
152 maRect
.SetPos( Point( 0, 0 ) );
153 maRect
.SetSize( rSize
);
154 mnCenterX
= rSize
.Width() / 2;
155 mnCenterY
= rSize
.Height() / 2;
156 SetOutputSize( rSize
);
159 void DialControlBmp::DrawBackground()
161 // *** background with 3D effect ***
167 EnableRTL( true ); // draw 3D effect in correct direction
169 sal_uInt8 nDiff
= mbEnabled
? 0x18 : 0x10;
172 aColor
= GetBackgroundColor();
173 SetFillColor( aColor
);
174 DrawPie( maRect
, maRect
.TopRight(), maRect
.TopCenter() );
175 DrawPie( maRect
, maRect
.BottomLeft(), maRect
.BottomCenter() );
177 aColor
.DecreaseLuminance( nDiff
);
178 SetFillColor( aColor
);
179 DrawPie( maRect
, maRect
.BottomCenter(), maRect
.TopRight() );
181 aColor
.DecreaseLuminance( nDiff
);
182 SetFillColor( aColor
);
183 DrawPie( maRect
, maRect
.BottomRight(), maRect
.RightCenter() );
185 aColor
= GetBackgroundColor();
186 aColor
.IncreaseLuminance( nDiff
);
187 SetFillColor( aColor
);
188 DrawPie( maRect
, maRect
.TopCenter(), maRect
.BottomLeft() );
190 aColor
.IncreaseLuminance( nDiff
);
191 SetFillColor( aColor
);
192 DrawPie( maRect
, maRect
.TopLeft(), maRect
.LeftCenter() );
196 // *** calibration ***
198 Point
aStartPos( mnCenterX
, mnCenterY
);
199 Color
aFullColor( GetScaleLineColor() );
200 Color
aLightColor( GetBackgroundColor() );
201 aLightColor
.Merge( aFullColor
, 128 );
203 for( int nAngle
= 0; nAngle
< 360; nAngle
+= 15 )
205 SetLineColor( (nAngle
% 45) ? aLightColor
: aFullColor
);
206 double fAngle
= nAngle
* F_PI180
;
207 long nX
= static_cast< long >( -mnCenterX
* cos( fAngle
) );
208 long nY
= static_cast< long >( mnCenterY
* sin( fAngle
) );
209 DrawLine( aStartPos
, Point( mnCenterX
- nX
, mnCenterY
- nY
) );
212 // *** clear inner area ***
215 SetFillColor( GetBackgroundColor() );
216 DrawEllipse( Rectangle( maRect
.Left() + DIAL_OUTER_WIDTH
, maRect
.Top() + DIAL_OUTER_WIDTH
,
217 maRect
.Right() - DIAL_OUTER_WIDTH
, maRect
.Bottom() - DIAL_OUTER_WIDTH
) );
222 DialControl::DialControl_Impl::DialControl_Impl ( vcl::Window
& rParent
) :
223 mxBmpEnabled(VclPtr
<DialControlBmp
>::Create(rParent
)),
224 mxBmpDisabled(VclPtr
<DialControlBmp
>::Create(rParent
)),
225 mxBmpBuffered(VclPtr
<DialControlBmp
>::Create(rParent
)),
227 mnLinkedFieldValueMultiplyer( 0 ),
237 void DialControl::DialControl_Impl::Init( const Size
& rWinSize
, const vcl::Font
& rWinFont
)
239 maWinFont
= rWinFont
;
240 maWinFont
.SetTransparent(true);
241 mxBmpBuffered
->InitBitmap(maWinFont
);
245 void DialControl::DialControl_Impl::SetSize( const Size
& rWinSize
)
247 // make the control squared, and adjusted so that we have a well-defined
248 // center ["(x - 1) | 1" creates odd value <= x]
249 long nMin
= (std::min(rWinSize
.Width(), rWinSize
.Height()) - 1) | 1;
251 maWinSize
= Size( nMin
, nMin
);
253 mnCenterX
= maWinSize
.Width() / 2;
254 mnCenterY
= maWinSize
.Height() / 2;
256 mxBmpEnabled
->DrawBackground( maWinSize
, true );
257 mxBmpDisabled
->DrawBackground( maWinSize
, false );
258 mxBmpBuffered
->SetSize( maWinSize
);
263 DialControl::DialControl( vcl::Window
* pParent
, WinBits nBits
) :
264 Control( pParent
, nBits
),
265 mpImpl( new DialControl_Impl( *this ) )
267 Init( GetOutputSizePixel() );
270 VCL_BUILDER_FACTORY_ARGS(DialControl
, WB_TABSTOP
)
272 void DialControl::Resize()
274 mpImpl
->SetSize(GetOutputSizePixel());
278 void DialControl::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
&)
281 rRenderContext
.DrawBitmapEx(aPos
, mpImpl
->mxBmpBuffered
->GetBitmapEx(aPos
, mpImpl
->maWinSize
));
284 void DialControl::StateChanged( StateChangedType nStateChange
)
286 if( nStateChange
== StateChangedType::Enable
)
289 // update the linked edit field
290 if( mpImpl
->mpLinkField
)
292 NumericField
& rField
= *mpImpl
->mpLinkField
;
293 switch( nStateChange
)
295 case StateChangedType::Visible
: rField
.Show( IsVisible() ); break;
296 case StateChangedType::Enable
: rField
.Enable( IsEnabled() ); break;
301 Control::StateChanged( nStateChange
);
304 void DialControl::DataChanged( const DataChangedEvent
& rDCEvt
)
306 if( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) && (rDCEvt
.GetFlags() & AllSettingsFlags::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 vcl::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( "" );
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
= 100 / std::pow(10.0, double(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 void DialControl::SetModifyHdl( const Link
<>& rLink
)
415 mpImpl
->maModifyHdl
= rLink
;
418 void DialControl::Init( const Size
& rWinSize
, const vcl::Font
& rWinFont
)
420 mpImpl
->Init( rWinSize
, rWinFont
);
421 EnableRTL( false ); // don't mirror mouse handling
422 SetOutputSizePixel( mpImpl
->maWinSize
);
426 void DialControl::Init( const Size
& rWinSize
)
428 //hidpi TODO: GetDefaultFont() picks a font size too small, so fix it here.
429 vcl::Font aDefaultSize
= GetFont();
431 vcl::Font
aFont( OutputDevice::GetDefaultFont(
432 DefaultFontType::UI_SANS
, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne
) );
434 aFont
.SetHeight(aDefaultSize
.GetHeight());
435 Init( rWinSize
, aFont
);
438 void DialControl::InvalidateControl()
440 mpImpl
->mxBmpBuffered
->CopyBackground( IsEnabled() ? *mpImpl
->mxBmpEnabled
: *mpImpl
->mxBmpDisabled
);
441 if( !mpImpl
->mbNoRot
)
442 mpImpl
->mxBmpBuffered
->DrawElements( GetText(), mpImpl
->mnAngle
);
446 void DialControl::SetRotation( sal_Int32 nAngle
, bool bBroadcast
)
448 bool bOldSel
= mpImpl
->mbNoRot
;
449 mpImpl
->mbNoRot
= false;
454 if( !bOldSel
|| (mpImpl
->mnAngle
!= nAngle
) )
456 mpImpl
->mnAngle
= nAngle
;
458 if( mpImpl
->mpLinkField
)
459 mpImpl
->mpLinkField
->SetValue( static_cast< long >( GetRotation() / mpImpl
->mnLinkedFieldValueMultiplyer
) );
461 mpImpl
->maModifyHdl
.Call( this );
465 void DialControl::ImplSetFieldLink( const Link
<>& rLink
)
467 if( mpImpl
->mpLinkField
)
469 NumericField
& rField
= *mpImpl
->mpLinkField
;
470 rField
.SetModifyHdl( rLink
);
471 rField
.SetUpHdl( rLink
);
472 rField
.SetDownHdl( rLink
);
473 rField
.SetFirstHdl( rLink
);
474 rField
.SetLastHdl( rLink
);
475 rField
.SetLoseFocusHdl( rLink
);
479 void DialControl::HandleMouseEvent( const Point
& rPos
, bool bInitial
)
481 long nX
= rPos
.X() - mpImpl
->mnCenterX
;
482 long nY
= mpImpl
->mnCenterY
- rPos
.Y();
483 double fH
= sqrt( static_cast< double >( nX
) * nX
+ static_cast< double >( nY
) * nY
);
486 double fAngle
= acos( nX
/ fH
);
487 sal_Int32 nAngle
= static_cast< sal_Int32
>( fAngle
/ F_PI180
* 100.0 );
489 nAngle
= 36000 - nAngle
;
490 if( bInitial
) // round to entire 15 degrees
491 nAngle
= ((nAngle
+ 750) / 1500) * 1500;
492 // Round up to 1 degree
493 nAngle
= (((nAngle
+ 50) / 100) * 100) % 36000;
494 SetRotation( nAngle
, true );
498 void DialControl::HandleEscapeEvent()
500 if( IsMouseCaptured() )
503 SetRotation( mpImpl
->mnOldAngle
, true );
504 if( mpImpl
->mpLinkField
)
505 mpImpl
->mpLinkField
->GrabFocus();
509 IMPL_LINK( DialControl
, LinkedFieldModifyHdl
, NumericField
*, pField
)
512 SetRotation( static_cast< sal_Int32
>( pField
->GetValue() * mpImpl
->mnLinkedFieldValueMultiplyer
), false );
518 DialControlWrapper::DialControlWrapper( DialControl
& rDial
) :
519 SingleControlWrapperType( rDial
)
523 bool DialControlWrapper::IsControlDontKnow() const
525 return !GetControl().HasRotation();
528 void DialControlWrapper::SetControlDontKnow( bool bSet
)
531 GetControl().SetNoRotation();
534 sal_Int32
DialControlWrapper::GetControlValue() const
536 return GetControl().GetRotation();
539 void DialControlWrapper::SetControlValue( sal_Int32 nValue
)
541 GetControl().SetRotation( nValue
);
548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */