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