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