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