1///////////////////////////////////////////////////////////////////////////// 2// Name: hintanimpl.cpp 3// Purpose: cbHintAnimationPlugin implementation. 4// Author: Aleksandras Gluchovas 5// Modified by: 6// Created: 9/11/98 7// RCS-ID: $Id: hintanimpl.cpp 35650 2005-09-23 12:56:45Z MR $ 8// Copyright: (c) Aleksandras Gluchovas 9// Licence: wxWindows license 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16#pragma hdrstop 17#endif 18 19#ifndef WX_PRECOMP 20#include "wx/wx.h" 21#endif 22 23#include "wx/fl/hintanimpl.h" 24 25#define POS_UNDEFINED -32768 26 27/***** Implementation for class cbHintAnimationPlugin *****/ 28 29// FIXME:: some of the below code should be eliminated by 30// reusing parts of cbBarDragPlugin's implementation 31 32IMPLEMENT_DYNAMIC_CLASS( cbHintAnimationPlugin, cbPluginBase ) 33 34BEGIN_EVENT_TABLE( cbHintAnimationPlugin, cbPluginBase ) 35 36 EVT_PL_DRAW_HINT_RECT( cbHintAnimationPlugin::OnDrawHintRect ) 37 38END_EVENT_TABLE() 39 40cbHintAnimationPlugin::cbHintAnimationPlugin(void) 41 42 : mpScrDc( NULL ), 43 mpAnimTimer( 0 ), 44 mAnimStarted( false ), 45 46 mMorphDelay ( 5 ), 47 mMaxFrames ( 20 ), 48 mInClientHintBorder( 4 ), 49 mAccelerationOn( true ) 50{} 51 52cbHintAnimationPlugin::cbHintAnimationPlugin( wxFrameLayout* pPanel, int paneMask ) 53 54 : cbPluginBase( pPanel, paneMask ), 55 mpScrDc( NULL ), 56 mpAnimTimer( 0 ), 57 mAnimStarted( false ), 58 59 mMorphDelay ( 5 ), 60 mMaxFrames ( 20 ), 61 mInClientHintBorder( 4 ), 62 mAccelerationOn( true ) 63{} 64 65cbHintAnimationPlugin::~cbHintAnimationPlugin() 66{ 67 if ( mpScrDc ) delete mpScrDc; 68} 69 70/*** rect-tracking related methods ***/ 71 72void cbHintAnimationPlugin::OnDrawHintRect( cbDrawHintRectEvent& event ) 73{ 74 if ( !mAnimStarted && !mpScrDc ) 75 { 76 StartTracking(); 77 78 mPrevInClient = event.mIsInClient; 79 80 mPrevRect = event.mRect; 81 82 mStopPending = false; 83 } 84 85 if ( !event.mEraseRect ) 86 { 87 // pass on current hint-rect info to the animation "thread", in 88 // order to make adjustments to the morph-target on-the-fly 89 90 mCurRect.x = event.mRect.x; 91 mCurRect.y = event.mRect.y; 92 mCurRect.width = event.mRect.width; 93 mCurRect.height = event.mRect.height; 94 } 95 96 // check the amount of change in the shape of hint, 97 // and start morph-effect if change is "sufficient" 98 99 int change = abs( mCurRect.width - mPrevRect.width ) + 100 abs( mCurRect.height - mPrevRect.height ); 101 102 if ( change > 10 && !event.mLastTime && !event.mEraseRect ) 103 { 104 if ( !mpAnimTimer ) 105 106 mpAnimTimer = new cbHintAnimTimer(); 107 108 // init the animation "thread", or reinit if already started 109 110 mpAnimTimer->Init( this, mAnimStarted ); 111 112 mAnimStarted = true; 113 } 114 else 115 if ( !mAnimStarted ) 116 { 117 DoDrawHintRect( event.mRect, event.mIsInClient ); 118 119 if ( event.mLastTime ) 120 121 FinishTracking(); 122 123 mPrevInClient = event.mIsInClient; 124 } 125 else 126 { 127 mCurInClient = event.mIsInClient; 128 129 if ( event.mLastTime && mpAnimTimer ) 130 { 131 mStopPending = true; 132 133 if ( mpAnimTimer->mPrevMorphed.x != POS_UNDEFINED ) 134 135 // erase previous rect 136 DoDrawHintRect( mpAnimTimer->mPrevMorphed, mPrevInClient ); 137 } 138 } 139 140 mPrevRect = event.mRect; 141} 142 143#define _IMG_A 0xAA // Note: modified from _A to _IMG_A, _A was already defined (cygwin) 144#define _IMG_B 0x00 // Note: modified from _B to _IMG_A, _B was already defined (cygwin) 145#define _IMG_C 0x55 // Note: modified from _C to _IMG_C, for consistency reasons. 146#define _IMG_D 0x00 // Note: modified from _D to _IMG_D, for consistency reasons. 147 148static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D, 149 _IMG_A,_IMG_B,_IMG_C,_IMG_D, 150 _IMG_A,_IMG_B,_IMG_C,_IMG_D, 151 _IMG_A,_IMG_B,_IMG_C,_IMG_D 152 }; 153 154void cbHintAnimationPlugin::StartTracking() 155{ 156 mpScrDc = new wxScreenDC; 157 158 wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame()); 159} 160 161void cbHintAnimationPlugin::DoDrawHintRect( wxRect& rect, bool isInClientRect) 162{ 163 wxRect scrRect; 164 165 RectToScr( rect, scrRect ); 166 167 int prevLF = mpScrDc->GetLogicalFunction(); 168 169 mpScrDc->SetLogicalFunction( wxXOR ); 170 171 if ( isInClientRect ) 172 { 173 // BUG BUG BUG (wx):: somehow stippled brush works only 174 // when the bitmap created on stack, not 175 // as a member of the class 176 177 wxBitmap checker( (const char*)_gCheckerImg, 8,8 ); 178 179 wxBrush checkerBrush( checker ); 180 181 mpScrDc->SetPen( mpLayout->mNullPen ); 182 mpScrDc->SetBrush( checkerBrush ); 183 184 int half = mInClientHintBorder / 2; 185 186 mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y - half, 187 scrRect.width + 2*half, mInClientHintBorder ); 188 189 mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + scrRect.height - half, 190 scrRect.width + 2*half, mInClientHintBorder ); 191 192 mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + half - 1, 193 mInClientHintBorder, scrRect.height - 2*half + 2); 194 195 mpScrDc->DrawRectangle( scrRect.x + scrRect.width - half, 196 scrRect.y + half - 1, 197 mInClientHintBorder, scrRect.height - 2*half + 2); 198 199 mpScrDc->SetBrush( wxNullBrush ); 200 } 201 else 202 { 203 // otherwise draw 1-pixel thin borders 204 205 mpScrDc->SetPen( mpLayout->mBlackPen ); 206 207 mpScrDc->DrawLine( scrRect.x, scrRect.y, 208 scrRect.x + scrRect.width, scrRect.y ); 209 210 mpScrDc->DrawLine( scrRect.x, scrRect.y + 1, 211 scrRect.x, scrRect.y + scrRect.height ); 212 213 mpScrDc->DrawLine( scrRect.x+1, scrRect.y + scrRect.height, 214 scrRect.x + scrRect.width, scrRect.y + scrRect.height ); 215 216 mpScrDc->DrawLine( scrRect.x + scrRect.width , scrRect.y, 217 scrRect.x + scrRect.width, scrRect.y + scrRect.height + 1); 218 } 219 220 mpScrDc->SetLogicalFunction( prevLF ); 221} 222 223void cbHintAnimationPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect) 224{ 225 DoDrawHintRect( rect, isInClientRect ); 226} 227 228void cbHintAnimationPlugin::EraseHintRect( wxRect& rect, bool isInClientRect) 229{ 230 DoDrawHintRect( rect, isInClientRect ); 231} 232 233void cbHintAnimationPlugin::FinishTracking() 234{ 235 wxScreenDC::EndDrawingOnTop(); 236 237 delete mpScrDc; 238 239 mpScrDc = NULL; 240} 241 242void cbHintAnimationPlugin::RectToScr( wxRect& frameRect, wxRect& scrRect ) 243{ 244 scrRect = frameRect; 245 246 int x = frameRect.x, y = frameRect.y; 247 248 mpLayout->GetParentFrame().ClientToScreen( &x, &y ); 249 250 scrRect.x = x; 251 scrRect.y = y; 252} 253 254/***** Implementation for class cbHintAnimTimer *****/ 255 256cbHintAnimTimer::cbHintAnimTimer(void) 257{ 258#ifdef __WINDOWS__ 259 mLock = 0L; 260#endif 261 262 mPrevMorphed.x = POS_UNDEFINED; 263} 264 265void cbHintAnimTimer::MorphPoint( wxPoint& origin, MorphInfoT& info, wxPoint& point ) 266{ 267 // simulate lienar movement (FOR NOW:: without acceleration) 268 269 double k; 270 271 if ( mpPl->mAccelerationOn ) 272 273 k = double( mCurIter*mCurIter ) / 274 double( (mpPl->mMaxFrames - 1)*(mpPl->mMaxFrames - 1) ); 275 else 276 k = double( mCurIter ) / double( mpPl->mMaxFrames - 1 ); 277 278 point.x = int ( double ( info.mFrom.x + double (info.mTill.x - info.mFrom.x) * k ) ); 279 280 point.y = int ( double ( info.mFrom.y + double (info.mTill.y - info.mFrom.y) * k ) ); 281 282 point.x += origin.x; 283 point.y += origin.y; 284} 285 286void cbHintAnimTimer::Notify(void) 287{ 288 // FIXME:: "clean" implementation should use mutex to sync 289 // between GUI and animation threads 290 291 if ( mpPl->mStopPending ) 292 { 293 Stop(); // top timer 294 295 mpPl->FinishTracking(); 296 297 mpPl->mStopPending = false; 298 mpPl->mpAnimTimer = NULL; 299 mpPl->mAnimStarted = false; 300 301 mPrevMorphed.x = POS_UNDEFINED; 302 303 delete this; 304 305 return; 306 } 307 308 wxPoint origin( mpPl->mCurRect.x, mpPl->mCurRect.y ); 309 310 wxPoint curUpper, curLower; 311 312 MorphPoint( origin, mUpperLeft, curUpper ); 313 MorphPoint( origin, mLowerRight, curLower ); 314 315 if ( mPrevMorphed.x != POS_UNDEFINED ) 316 317 // erase previous rect 318 mpPl->DoDrawHintRect( mPrevMorphed, mpPl->mPrevInClient ); 319 320 wxRect morphed( curUpper.x, curUpper.y, 321 curLower.x - curUpper.x, 322 curLower.y - curUpper.y ); 323 324 // draw rect of current iteration 325 mpPl->DoDrawHintRect( morphed, 326 ( mCurIter != mpPl->mMaxFrames - 1 ) 327 ? mpPl->mPrevInClient : mpPl->mCurInClient ); 328 329 mPrevMorphed = morphed; 330 331 if ( mCurIter == mpPl->mMaxFrames - 1 ) 332 { 333 Stop(); // top timer 334 335 mpPl->FinishTracking(); 336 mpPl->mpAnimTimer = NULL; 337 mpPl->mAnimStarted = false; 338 339 mPrevMorphed.x = POS_UNDEFINED; 340 341 delete this; 342 } 343 else 344 ++mCurIter; 345} 346 347bool cbHintAnimTimer::Init( cbHintAnimationPlugin* pAnimPl, bool reinit ) 348{ 349 350 mpPl = pAnimPl; 351 352 // morph-points are set up relatively to the upper-left corner 353 // of the current hint-rectangle 354 355 if ( !reinit ) 356 { 357 mUpperLeft.mFrom.x = mpPl->mPrevRect.x - mpPl->mCurRect.x; 358 mUpperLeft.mFrom.y = mpPl->mPrevRect.y - mpPl->mCurRect.y; 359 360 mLowerRight.mFrom.x = ( mUpperLeft.mFrom.x + mpPl->mPrevRect.width ); 361 mLowerRight.mFrom.y = ( mUpperLeft.mFrom.y + mpPl->mPrevRect.height ); 362 } 363 else 364 { 365 wxPoint origin( mpPl->mPrevRect.x, mpPl->mPrevRect.y ); 366 367 wxPoint curUpper, curLower; 368 369 MorphPoint( origin, mUpperLeft, curUpper ); 370 MorphPoint( origin, mLowerRight, curLower ); 371 372 mUpperLeft.mFrom.x = curUpper.x - mpPl->mCurRect.x; 373 mUpperLeft.mFrom.y = curUpper.y - mpPl->mCurRect.y; 374 375 mLowerRight.mFrom.x = ( mUpperLeft.mFrom.x + curLower.x - curUpper.x ); 376 mLowerRight.mFrom.y = ( mUpperLeft.mFrom.y + curLower.y - curUpper.y ); 377 } 378 379 mUpperLeft.mTill.x = 0; 380 mUpperLeft.mTill.y = 0; 381 382 mLowerRight.mTill.x = mpPl->mCurRect.width; 383 mLowerRight.mTill.y = mpPl->mCurRect.height; 384 385 mCurIter = 1; 386 387 if ( !reinit ) 388 389 Start( mpPl->mMorphDelay ); 390 391 return true; 392} 393 394