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 48 DialControlBmp::DialControlBmp( Window& rParent ) : 49 VirtualDevice( rParent, 0, 0 ), 50 mbEnabled( true ), 51 mrParent( rParent ) 52 { 53 EnableRTL( sal_False ); 54 } 55 56 void DialControlBmp::InitBitmap( const Size& rSize, const Font& rFont ) 57 { 58 Init( rSize ); 59 SetFont( rFont ); 60 } 61 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 70 void DialControlBmp::DrawBackground( const Size& rSize, bool bEnabled ) 71 { 72 Init( rSize ); 73 mbEnabled = bEnabled; 74 DrawBackground(); 75 } 76 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 111 const Color& DialControlBmp::GetBackgroundColor() const 112 { 113 return GetSettings().GetStyleSettings().GetDialogColor(); 114 } 115 116 const Color& DialControlBmp::GetTextColor() const 117 { 118 return GetSettings().GetStyleSettings().GetLabelTextColor(); 119 } 120 121 const Color& DialControlBmp::GetScaleLineColor() const 122 { 123 const StyleSettings& rSett = GetSettings().GetStyleSettings(); 124 return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor(); 125 } 126 127 const Color& DialControlBmp::GetButtonLineColor() const 128 { 129 const StyleSettings& rSett = GetSettings().GetStyleSettings(); 130 return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor(); 131 } 132 133 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 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 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 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 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 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 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 261 DialControl::DialControl( Window* pParent, const ResId& rResId ) : 262 Control( pParent, rResId ), 263 mpImpl( new DialControl_Impl( *this ) ) 264 { 265 Init( GetOutputSizePixel() ); 266 } 267 268 DialControl::~DialControl() 269 { 270 } 271 272 void DialControl::Paint( const Rectangle& ) 273 { 274 Point aPos; 275 DrawBitmapEx( aPos, mpImpl->mpBmpBuffered->GetBitmapEx( aPos, mpImpl->maWinSize ) ); 276 } 277 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 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 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 319 void DialControl::MouseMove( const MouseEvent& rMEvt ) 320 { 321 if( IsMouseCaptured() && rMEvt.IsLeft() ) 322 HandleMouseEvent( rMEvt.GetPosPixel(), false ); 323 Control::MouseMove(rMEvt ); 324 } 325 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 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 346 void DialControl::LoseFocus() 347 { 348 // release captured mouse 349 HandleEscapeEvent(); 350 Control::LoseFocus(); 351 } 352 353 bool DialControl::HasRotation() const 354 { 355 return !mpImpl->mbNoRot; 356 } 357 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 369 sal_Int32 DialControl::GetRotation() const 370 { 371 return mpImpl->mnAngle; 372 } 373 374 void DialControl::SetRotation( sal_Int32 nAngle ) 375 { 376 SetRotation( nAngle, false ); 377 } 378 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 389 NumericField* DialControl::GetLinkedField() const 390 { 391 return mpImpl->mpLinkField; 392 } 393 394 void DialControl::SetModifyHdl( const Link& rLink ) 395 { 396 mpImpl->maModifyHdl = rLink; 397 } 398 399 const Link& DialControl::GetModifyHdl() const 400 { 401 return mpImpl->maModifyHdl; 402 } 403 404 // private -------------------------------------------------------------------- 405 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 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 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 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 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 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 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 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 498 DialControlWrapper::DialControlWrapper( DialControl& rDial ) : 499 SingleControlWrapperType( rDial ) 500 { 501 } 502 503 bool DialControlWrapper::IsControlDontKnow() const 504 { 505 return !GetControl().HasRotation(); 506 } 507 508 void DialControlWrapper::SetControlDontKnow( bool bSet ) 509 { 510 if( bSet ) 511 GetControl().SetNoRotation(); 512 } 513 514 sal_Int32 DialControlWrapper::GetControlValue() const 515 { 516 return GetControl().GetRotation(); 517 } 518 519 void DialControlWrapper::SetControlValue( sal_Int32 nValue ) 520 { 521 GetControl().SetRotation( nValue ); 522 } 523 524 // ============================================================================ 525 526 } // namespace svx 527 528