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