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