xref: /aoo42x/main/svx/source/dialog/dialcontrol.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include "svx/dialcontrol.hxx"
31 
32 #include <math.h>
33 #include <vcl/virdev.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/bitmap.hxx>
36 #include <vcl/field.hxx>
37 #include <svtools/colorcfg.hxx>
38 
39 namespace svx {
40 
41 // ============================================================================
42 
43 const long DIAL_OUTER_WIDTH = 8;
44 
45 // ============================================================================
46 
47 class DialControlBmp : public VirtualDevice
48 {
49 public:
50     explicit            DialControlBmp( Window& rParent );
51 
52     void                InitBitmap( const Size& rSize, const Font& rFont );
53     void                CopyBackground( const DialControlBmp& rSrc );
54     void                DrawBackground( const Size& rSize, bool bEnabled );
55     void                DrawElements( const String& rText, sal_Int32 nAngle );
56 
57 private:
58     const Color&        GetBackgroundColor() const;
59     const Color&        GetTextColor() const;
60     const Color&        GetScaleLineColor() const;
61     const Color&        GetButtonLineColor() const;
62     const Color&        GetButtonFillColor( bool bMain ) const;
63 
64     void                Init( const Size& rSize );
65     void                DrawBackground();
66 
67     Window&             mrParent;
68     Rectangle           maRect;
69     long                mnCenterX;
70     long                mnCenterY;
71     bool                mbEnabled;
72 };
73 
74 // ----------------------------------------------------------------------------
75 
76 DialControlBmp::DialControlBmp( Window& rParent ) :
77     VirtualDevice( rParent, 0, 0 ),
78     mrParent( rParent ),
79     mbEnabled( true )
80 {
81     EnableRTL( sal_False );
82 }
83 
84 void DialControlBmp::InitBitmap( const Size& rSize, const Font& rFont )
85 {
86     Init( rSize );
87     SetFont( rFont );
88 }
89 
90 void DialControlBmp::CopyBackground( const DialControlBmp& rSrc )
91 {
92     Init( rSrc.maRect.GetSize() );
93     mbEnabled = rSrc.mbEnabled;
94     Point aPos;
95     DrawBitmapEx( aPos, rSrc.GetBitmapEx( aPos, maRect.GetSize() ) );
96 }
97 
98 void DialControlBmp::DrawBackground( const Size& rSize, bool bEnabled )
99 {
100     Init( rSize );
101     mbEnabled = bEnabled;
102     DrawBackground();
103 }
104 
105 void DialControlBmp::DrawElements( const String& rText, sal_Int32 nAngle )
106 {
107     // *** rotated text ***
108 
109     Font aFont( GetFont() );
110     aFont.SetColor( GetTextColor() );
111     aFont.SetOrientation( static_cast< short >( (nAngle + 5) / 10 ) );  // Font uses 1/10 degrees
112     aFont.SetWeight( WEIGHT_BOLD );
113     SetFont( aFont );
114 
115     double fAngle = nAngle * F_PI180 / 100.0;
116     double fSin = sin( fAngle );
117     double fCos = cos( fAngle );
118     double fWidth = GetTextWidth( rText ) / 2.0;
119     double fHeight = GetTextHeight() / 2.0;
120     long nX = static_cast< long >( mnCenterX - fWidth * fCos - fHeight * fSin );
121     long nY = static_cast< long >( mnCenterY + fWidth * fSin - fHeight * fCos );
122     Rectangle aRect( nX, nY, 2 * mnCenterX - nX, 2 * mnCenterY - nY );
123     DrawText( aRect, rText, mbEnabled ? 0 : TEXT_DRAW_DISABLE );
124 
125     // *** drag button ***
126 
127     bool bMain = (nAngle % 4500) != 0;
128     SetLineColor( GetButtonLineColor() );
129     SetFillColor( GetButtonFillColor( bMain ) );
130 
131     nX = mnCenterX - static_cast< long >( (DIAL_OUTER_WIDTH / 2 - mnCenterX) * fCos );
132     nY = mnCenterY - static_cast< long >( (mnCenterY - DIAL_OUTER_WIDTH / 2) * fSin );
133     long nSize = bMain ? (DIAL_OUTER_WIDTH / 4) : (DIAL_OUTER_WIDTH / 2 - 1);
134     DrawEllipse( Rectangle( nX - nSize, nY - nSize, nX + nSize, nY + nSize ) );
135 }
136 
137 // private --------------------------------------------------------------------
138 
139 const Color& DialControlBmp::GetBackgroundColor() const
140 {
141     return GetSettings().GetStyleSettings().GetDialogColor();
142 }
143 
144 const Color& DialControlBmp::GetTextColor() const
145 {
146     return GetSettings().GetStyleSettings().GetLabelTextColor();
147 }
148 
149 const Color& DialControlBmp::GetScaleLineColor() const
150 {
151     const StyleSettings& rSett = GetSettings().GetStyleSettings();
152     return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
153 }
154 
155 const Color& DialControlBmp::GetButtonLineColor() const
156 {
157     const StyleSettings& rSett = GetSettings().GetStyleSettings();
158     return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
159 }
160 
161 const Color& DialControlBmp::GetButtonFillColor( bool bMain ) const
162 {
163     const StyleSettings& rSett = GetSettings().GetStyleSettings();
164     return mbEnabled ? (bMain ? rSett.GetMenuColor() : rSett.GetHighlightColor()) : rSett.GetDisableColor();
165 }
166 
167 void DialControlBmp::Init( const Size& rSize )
168 {
169     SetSettings( mrParent.GetSettings() );
170     maRect.SetPos( Point( 0, 0 ) );
171     maRect.SetSize( rSize );
172     mnCenterX = rSize.Width() / 2;
173     mnCenterY = rSize.Height() / 2;
174     SetOutputSize( rSize );
175     SetBackground();
176 }
177 
178 void DialControlBmp::DrawBackground()
179 {
180     // *** background with 3D effect ***
181 
182     SetLineColor();
183     SetFillColor();
184     Erase();
185 
186     EnableRTL( sal_True ); // #107807# draw 3D effect in correct direction
187 
188     sal_uInt8 nDiff = mbEnabled ? 0x18 : 0x10;
189     Color aColor;
190 
191     aColor = GetBackgroundColor();
192     SetFillColor( aColor );
193     DrawPie( maRect, maRect.TopRight(), maRect.TopCenter() );
194     DrawPie( maRect, maRect.BottomLeft(), maRect.BottomCenter() );
195 
196     aColor.DecreaseLuminance( nDiff );
197     SetFillColor( aColor );
198     DrawPie( maRect, maRect.BottomCenter(), maRect.TopRight() );
199 
200     aColor.DecreaseLuminance( nDiff );
201     SetFillColor( aColor );
202     DrawPie( maRect, maRect.BottomRight(), maRect.RightCenter() );
203 
204     aColor = GetBackgroundColor();
205     aColor.IncreaseLuminance( nDiff );
206     SetFillColor( aColor );
207     DrawPie( maRect, maRect.TopCenter(), maRect.BottomLeft() );
208 
209     aColor.IncreaseLuminance( nDiff );
210     SetFillColor( aColor );
211     DrawPie( maRect, maRect.TopLeft(), maRect.LeftCenter() );
212 
213     EnableRTL( sal_False );
214 
215     // *** calibration ***
216 
217     Point aStartPos( mnCenterX, mnCenterY );
218     Color aFullColor( GetScaleLineColor() );
219     Color aLightColor( GetBackgroundColor() );
220     aLightColor.Merge( aFullColor, 128 );
221 
222     for( int nAngle = 0; nAngle < 360; nAngle += 15 )
223     {
224         SetLineColor( (nAngle % 45) ? aLightColor : aFullColor );
225         double fAngle = nAngle * F_PI180;
226         long nX = static_cast< long >( -mnCenterX * cos( fAngle ) );
227         long nY = static_cast< long >( mnCenterY * sin( fAngle ) );
228         DrawLine( aStartPos, Point( mnCenterX - nX, mnCenterY - nY ) );
229     }
230 
231     // *** clear inner area ***
232 
233     SetLineColor();
234     SetFillColor( GetBackgroundColor() );
235     DrawEllipse( Rectangle( maRect.Left() + DIAL_OUTER_WIDTH, maRect.Top() + DIAL_OUTER_WIDTH,
236         maRect.Right() - DIAL_OUTER_WIDTH, maRect.Bottom() - DIAL_OUTER_WIDTH ) );
237 }
238 
239 // ============================================================================
240 
241 struct DialControl_Impl
242 {
243     DialControlBmp      maBmpEnabled;
244     DialControlBmp      maBmpDisabled;
245     DialControlBmp      maBmpBuffered;
246     Link                maModifyHdl;
247     NumericField*       mpLinkField;
248     Size                maWinSize;
249     Font                maWinFont;
250     sal_Int32           mnAngle;
251     sal_Int32           mnOldAngle;
252     long                mnCenterX;
253     long                mnCenterY;
254     bool                mbNoRot;
255 
256     explicit            DialControl_Impl( Window& rParent );
257     void                Init( const Size& rWinSize, const Font& rWinFont );
258 };
259 
260 // ----------------------------------------------------------------------------
261 
262 DialControl_Impl::DialControl_Impl( Window& rParent ) :
263     maBmpEnabled( rParent ),
264     maBmpDisabled( rParent ),
265     maBmpBuffered( rParent ),
266     mpLinkField( 0 ),
267     mnAngle( 0 ),
268     mbNoRot( false )
269 {
270 }
271 
272 void DialControl_Impl::Init( const Size& rWinSize, const Font& rWinFont )
273 {
274     // "(x - 1) | 1" creates odd value <= x, to have a well-defined center pixel position
275     maWinSize = Size( (rWinSize.Width() - 1) | 1, (rWinSize.Height() - 1) | 1 );
276     maWinFont = rWinFont;
277 
278     mnCenterX = maWinSize.Width() / 2;
279     mnCenterY = maWinSize.Height() / 2;
280     maWinFont.SetTransparent( sal_True );
281 
282     maBmpEnabled.DrawBackground( maWinSize, true );
283     maBmpDisabled.DrawBackground( maWinSize, false );
284     maBmpBuffered.InitBitmap( maWinSize, maWinFont );
285 }
286 
287 // ============================================================================
288 
289 DialControl::DialControl( Window* pParent, const Size& rSize, const Font& rFont, WinBits nWinStyle ) :
290     Control( pParent, nWinStyle ),
291     mpImpl( new DialControl_Impl( *this ) )
292 {
293     Init( rSize, rFont );
294 }
295 
296 DialControl::DialControl( Window* pParent, const Size& rSize, WinBits nWinStyle ) :
297     Control( pParent, nWinStyle ),
298     mpImpl( new DialControl_Impl( *this ) )
299 {
300     if( pParent )
301         Init( rSize, pParent->GetFont() );
302     else
303         Init( rSize );
304 }
305 
306 DialControl::DialControl( Window* pParent, const ResId& rResId ) :
307     Control( pParent, rResId ),
308     mpImpl( new DialControl_Impl( *this ) )
309 {
310     Init( GetOutputSizePixel() );
311 }
312 
313 DialControl::~DialControl()
314 {
315 }
316 
317 void DialControl::Paint( const Rectangle&  )
318 {
319     Point aPos;
320     DrawBitmapEx( aPos, mpImpl->maBmpBuffered.GetBitmapEx( aPos, mpImpl->maWinSize ) );
321 }
322 
323 void DialControl::StateChanged( StateChangedType nStateChange )
324 {
325     if( nStateChange == STATE_CHANGE_ENABLE )
326         InvalidateControl();
327 
328     // update the linked edit field
329     if( mpImpl->mpLinkField )
330     {
331         NumericField& rField = *mpImpl->mpLinkField;
332         switch( nStateChange )
333         {
334             case STATE_CHANGE_VISIBLE:  rField.Show( IsVisible() );     break;
335             case STATE_CHANGE_ENABLE:   rField.Enable( IsEnabled() );   break;
336         }
337     }
338 
339     Control::StateChanged( nStateChange );
340 }
341 
342 void DialControl::DataChanged( const DataChangedEvent& rDCEvt )
343 {
344     if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
345     {
346         Init( mpImpl->maWinSize, mpImpl->maWinFont );
347         InvalidateControl();
348     }
349     Control::DataChanged( rDCEvt );
350 }
351 
352 void DialControl::MouseButtonDown( const MouseEvent& rMEvt )
353 {
354     if( rMEvt.IsLeft() )
355     {
356         GrabFocus();
357         CaptureMouse();
358         mpImpl->mnOldAngle = mpImpl->mnAngle;
359         HandleMouseEvent( rMEvt.GetPosPixel(), true );
360     }
361     Control::MouseButtonDown( rMEvt );
362 }
363 
364 void DialControl::MouseMove( const MouseEvent& rMEvt )
365 {
366     if( IsMouseCaptured() && rMEvt.IsLeft() )
367         HandleMouseEvent( rMEvt.GetPosPixel(), false );
368     Control::MouseMove(rMEvt );
369 }
370 
371 void DialControl::MouseButtonUp( const MouseEvent& rMEvt )
372 {
373     if( IsMouseCaptured() )
374     {
375         ReleaseMouse();
376         if( mpImpl->mpLinkField )
377             mpImpl->mpLinkField->GrabFocus();
378     }
379     Control::MouseButtonUp( rMEvt );
380 }
381 
382 void DialControl::KeyInput( const KeyEvent& rKEvt )
383 {
384     const KeyCode& rKCode = rKEvt.GetKeyCode();
385     if( !rKCode.GetModifier() && (rKCode.GetCode() == KEY_ESCAPE) )
386         HandleEscapeEvent();
387     else
388         Control::KeyInput( rKEvt );
389 }
390 
391 void DialControl::LoseFocus()
392 {
393     // release captured mouse
394     HandleEscapeEvent();
395     Control::LoseFocus();
396 }
397 
398 bool DialControl::HasRotation() const
399 {
400     return !mpImpl->mbNoRot;
401 }
402 
403 void DialControl::SetNoRotation()
404 {
405     if( !mpImpl->mbNoRot )
406     {
407         mpImpl->mbNoRot = true;
408         InvalidateControl();
409         if( mpImpl->mpLinkField )
410             mpImpl->mpLinkField->SetText( String() );
411     }
412 }
413 
414 sal_Int32 DialControl::GetRotation() const
415 {
416     return mpImpl->mnAngle;
417 }
418 
419 void DialControl::SetRotation( sal_Int32 nAngle )
420 {
421     ImplSetRotation( nAngle, false );
422 }
423 
424 void DialControl::SetLinkedField( NumericField* pField )
425 {
426     // remove modify handler from old linked field
427     ImplSetFieldLink( Link() );
428     // remember the new linked field
429     mpImpl->mpLinkField = pField;
430     // set modify handler at new linked field
431     ImplSetFieldLink( LINK( this, DialControl, LinkedFieldModifyHdl ) );
432 }
433 
434 NumericField* DialControl::GetLinkedField() const
435 {
436     return mpImpl->mpLinkField;
437 }
438 
439 void DialControl::SetModifyHdl( const Link& rLink )
440 {
441     mpImpl->maModifyHdl = rLink;
442 }
443 
444 const Link& DialControl::GetModifyHdl() const
445 {
446     return mpImpl->maModifyHdl;
447 }
448 
449 // private --------------------------------------------------------------------
450 
451 void DialControl::Init( const Size& rWinSize, const Font& rWinFont )
452 {
453     mpImpl->Init( rWinSize, rWinFont );
454     EnableRTL( sal_False ); // #107807# don't mirror mouse handling
455     SetOutputSizePixel( mpImpl->maWinSize );
456     SetBackground();
457 }
458 
459 void DialControl::Init( const Size& rWinSize )
460 {
461     Font aFont( OutputDevice::GetDefaultFont(
462         DEFAULTFONT_UI_SANS, Application::GetSettings().GetUILanguage(), DEFAULTFONT_FLAGS_ONLYONE ) );
463     Init( rWinSize, aFont );
464 }
465 
466 void DialControl::InvalidateControl()
467 {
468     mpImpl->maBmpBuffered.CopyBackground( IsEnabled() ? mpImpl->maBmpEnabled : mpImpl->maBmpDisabled );
469     if( !mpImpl->mbNoRot )
470         mpImpl->maBmpBuffered.DrawElements( GetText(), mpImpl->mnAngle );
471     Invalidate();
472 }
473 
474 void DialControl::ImplSetRotation( sal_Int32 nAngle, bool bBroadcast )
475 {
476     bool bOldSel = mpImpl->mbNoRot;
477     mpImpl->mbNoRot = false;
478 
479     while( nAngle < 0 ) nAngle += 36000;
480     nAngle = (((nAngle + 50) / 100) * 100) % 36000;
481     if( !bOldSel || (mpImpl->mnAngle != nAngle) )
482     {
483         mpImpl->mnAngle = nAngle;
484         InvalidateControl();
485         if( mpImpl->mpLinkField )
486             mpImpl->mpLinkField->SetValue( static_cast< long >( GetRotation() / 100 ) );
487         if( bBroadcast )
488             mpImpl->maModifyHdl.Call( this );
489     }
490 }
491 
492 void DialControl::ImplSetFieldLink( const Link& rLink )
493 {
494     if( mpImpl->mpLinkField )
495     {
496         NumericField& rField = *mpImpl->mpLinkField;
497         rField.SetModifyHdl( rLink );
498         rField.SetUpHdl( rLink );
499         rField.SetDownHdl( rLink );
500         rField.SetFirstHdl( rLink );
501         rField.SetLastHdl( rLink );
502         rField.SetLoseFocusHdl( rLink );
503     }
504 }
505 
506 void DialControl::HandleMouseEvent( const Point& rPos, bool bInitial )
507 {
508     long nX = rPos.X() - mpImpl->mnCenterX;
509     long nY = mpImpl->mnCenterY - rPos.Y();
510     double fH = sqrt( static_cast< double >( nX ) * nX + static_cast< double >( nY ) * nY );
511     if( fH != 0.0 )
512     {
513         double fAngle = acos( nX / fH );
514         sal_Int32 nAngle = static_cast< sal_Int32 >( fAngle / F_PI180 * 100.0 );
515         if( nY < 0 )
516             nAngle = 36000 - nAngle;
517         if( bInitial )  // round to entire 15 degrees
518             nAngle = ((nAngle + 750) / 1500) * 1500;
519         ImplSetRotation( nAngle, true );
520     }
521 }
522 
523 void DialControl::HandleEscapeEvent()
524 {
525     if( IsMouseCaptured() )
526     {
527         ReleaseMouse();
528         ImplSetRotation( mpImpl->mnOldAngle, true );
529         if( mpImpl->mpLinkField )
530             mpImpl->mpLinkField->GrabFocus();
531     }
532 }
533 
534 IMPL_LINK( DialControl, LinkedFieldModifyHdl, NumericField*, pField )
535 {
536     if( pField )
537         ImplSetRotation( static_cast< sal_Int32 >( pField->GetValue() * 100 ), false );
538     return 0;
539 }
540 
541 // ============================================================================
542 
543 DialControlWrapper::DialControlWrapper( DialControl& rDial ) :
544     SingleControlWrapperType( rDial )
545 {
546 }
547 
548 bool DialControlWrapper::IsControlDontKnow() const
549 {
550     return !GetControl().HasRotation();
551 }
552 
553 void DialControlWrapper::SetControlDontKnow( bool bSet )
554 {
555     if( bSet )
556         GetControl().SetNoRotation();
557 }
558 
559 sal_Int32 DialControlWrapper::GetControlValue() const
560 {
561     return GetControl().GetRotation();
562 }
563 
564 void DialControlWrapper::SetControlValue( sal_Int32 nValue )
565 {
566     GetControl().SetRotation( nValue );
567 }
568 
569 // ============================================================================
570 
571 } // namespace svx
572 
573