]>
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 | ||
8e08b761 JS |
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 | ||
32 | IMPLEMENT_DYNAMIC_CLASS( cbHintAnimationPlugin, cbPluginBase ) | |
33 | ||
34 | BEGIN_EVENT_TABLE( cbHintAnimationPlugin, cbPluginBase ) | |
35 | ||
4cbc57f0 | 36 | EVT_PL_DRAW_HINT_RECT( cbHintAnimationPlugin::OnDrawHintRect ) |
8e08b761 JS |
37 | |
38 | END_EVENT_TABLE() | |
39 | ||
40 | cbHintAnimationPlugin::cbHintAnimationPlugin(void) | |
41 | ||
4cbc57f0 JS |
42 | : mpScrDc( NULL ), |
43 | mpAnimTimer( 0 ), | |
c82c42d4 | 44 | mAnimStarted( false ), |
4cbc57f0 JS |
45 | |
46 | mMorphDelay ( 5 ), | |
47 | mMaxFrames ( 20 ), | |
8e08b761 | 48 | mInClientHintBorder( 4 ), |
c82c42d4 | 49 | mAccelerationOn( true ) |
8e08b761 JS |
50 | {} |
51 | ||
52 | cbHintAnimationPlugin::cbHintAnimationPlugin( wxFrameLayout* pPanel, int paneMask ) | |
53 | ||
4cbc57f0 JS |
54 | : cbPluginBase( pPanel, paneMask ), |
55 | mpScrDc( NULL ), | |
56 | mpAnimTimer( 0 ), | |
c82c42d4 | 57 | mAnimStarted( false ), |
8e08b761 | 58 | |
4cbc57f0 JS |
59 | mMorphDelay ( 5 ), |
60 | mMaxFrames ( 20 ), | |
61 | mInClientHintBorder( 4 ), | |
c82c42d4 | 62 | mAccelerationOn( true ) |
8e08b761 JS |
63 | {} |
64 | ||
65 | cbHintAnimationPlugin::~cbHintAnimationPlugin() | |
66 | { | |
4cbc57f0 | 67 | if ( mpScrDc ) delete mpScrDc; |
8e08b761 JS |
68 | } |
69 | ||
70 | /*** rect-tracking related methods ***/ | |
71 | ||
72 | void cbHintAnimationPlugin::OnDrawHintRect( cbDrawHintRectEvent& event ) | |
73 | { | |
4cbc57f0 JS |
74 | if ( !mAnimStarted && !mpScrDc ) |
75 | { | |
76 | StartTracking(); | |
8e08b761 | 77 | |
4cbc57f0 | 78 | mPrevInClient = event.mIsInClient; |
8e08b761 | 79 | |
4cbc57f0 | 80 | mPrevRect = event.mRect; |
8e08b761 | 81 | |
c82c42d4 | 82 | mStopPending = false; |
4cbc57f0 | 83 | } |
8e08b761 | 84 | |
4cbc57f0 JS |
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 | |
8e08b761 | 89 | |
4cbc57f0 JS |
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 | } | |
8e08b761 | 95 | |
4cbc57f0 JS |
96 | // check the amount of change in the shape of hint, |
97 | // and start morph-effect if change is "sufficient" | |
8e08b761 | 98 | |
4cbc57f0 JS |
99 | int change = abs( mCurRect.width - mPrevRect.width ) + |
100 | abs( mCurRect.height - mPrevRect.height ); | |
8e08b761 | 101 | |
4cbc57f0 JS |
102 | if ( change > 10 && !event.mLastTime && !event.mEraseRect ) |
103 | { | |
104 | if ( !mpAnimTimer ) | |
8e08b761 | 105 | |
4cbc57f0 | 106 | mpAnimTimer = new cbHintAnimTimer(); |
8e08b761 | 107 | |
4cbc57f0 | 108 | // init the animation "thread", or reinit if already started |
8e08b761 | 109 | |
4cbc57f0 | 110 | mpAnimTimer->Init( this, mAnimStarted ); |
8e08b761 | 111 | |
c82c42d4 | 112 | mAnimStarted = true; |
4cbc57f0 JS |
113 | } |
114 | else | |
115 | if ( !mAnimStarted ) | |
116 | { | |
117 | DoDrawHintRect( event.mRect, event.mIsInClient ); | |
8e08b761 | 118 | |
4cbc57f0 | 119 | if ( event.mLastTime ) |
8e08b761 | 120 | |
4cbc57f0 | 121 | FinishTracking(); |
8e08b761 | 122 | |
4cbc57f0 JS |
123 | mPrevInClient = event.mIsInClient; |
124 | } | |
125 | else | |
126 | { | |
127 | mCurInClient = event.mIsInClient; | |
8e08b761 | 128 | |
4cbc57f0 JS |
129 | if ( event.mLastTime && mpAnimTimer ) |
130 | { | |
c82c42d4 | 131 | mStopPending = true; |
8e08b761 | 132 | |
4cbc57f0 | 133 | if ( mpAnimTimer->mPrevMorphed.x != POS_UNDEFINED ) |
8e08b761 | 134 | |
4cbc57f0 JS |
135 | // erase previous rect |
136 | DoDrawHintRect( mpAnimTimer->mPrevMorphed, mPrevInClient ); | |
137 | } | |
138 | } | |
8e08b761 | 139 | |
4cbc57f0 | 140 | mPrevRect = event.mRect; |
8e08b761 JS |
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 | ||
148 | static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D, | |
4cbc57f0 JS |
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 | }; | |
8e08b761 JS |
153 | |
154 | void cbHintAnimationPlugin::StartTracking() | |
155 | { | |
4cbc57f0 | 156 | mpScrDc = new wxScreenDC; |
8e08b761 | 157 | |
4cbc57f0 | 158 | wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame()); |
8e08b761 JS |
159 | } |
160 | ||
161 | void cbHintAnimationPlugin::DoDrawHintRect( wxRect& rect, bool isInClientRect) | |
162 | { | |
4cbc57f0 | 163 | wxRect scrRect; |
8e08b761 | 164 | |
4cbc57f0 | 165 | RectToScr( rect, scrRect ); |
8e08b761 | 166 | |
4cbc57f0 | 167 | int prevLF = mpScrDc->GetLogicalFunction(); |
8e08b761 | 168 | |
4cbc57f0 | 169 | mpScrDc->SetLogicalFunction( wxXOR ); |
8e08b761 | 170 | |
4cbc57f0 JS |
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 | |
8e08b761 | 176 | |
4cbc57f0 | 177 | wxBitmap checker( (const char*)_gCheckerImg, 8,8 ); |
8e08b761 | 178 | |
4cbc57f0 | 179 | wxBrush checkerBrush( checker ); |
8e08b761 | 180 | |
4cbc57f0 JS |
181 | mpScrDc->SetPen( mpLayout->mNullPen ); |
182 | mpScrDc->SetBrush( checkerBrush ); | |
8e08b761 | 183 | |
4cbc57f0 | 184 | int half = mInClientHintBorder / 2; |
8e08b761 | 185 | |
4cbc57f0 JS |
186 | mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y - half, |
187 | scrRect.width + 2*half, mInClientHintBorder ); | |
8e08b761 | 188 | |
4cbc57f0 JS |
189 | mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + scrRect.height - half, |
190 | scrRect.width + 2*half, mInClientHintBorder ); | |
8e08b761 | 191 | |
4cbc57f0 JS |
192 | mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + half - 1, |
193 | mInClientHintBorder, scrRect.height - 2*half + 2); | |
8e08b761 | 194 | |
4cbc57f0 JS |
195 | mpScrDc->DrawRectangle( scrRect.x + scrRect.width - half, |
196 | scrRect.y + half - 1, | |
197 | mInClientHintBorder, scrRect.height - 2*half + 2); | |
8e08b761 | 198 | |
4cbc57f0 JS |
199 | mpScrDc->SetBrush( wxNullBrush ); |
200 | } | |
201 | else | |
202 | { | |
203 | // otherwise draw 1-pixel thin borders | |
8e08b761 | 204 | |
4cbc57f0 | 205 | mpScrDc->SetPen( mpLayout->mBlackPen ); |
8e08b761 | 206 | |
4cbc57f0 JS |
207 | mpScrDc->DrawLine( scrRect.x, scrRect.y, |
208 | scrRect.x + scrRect.width, scrRect.y ); | |
8e08b761 | 209 | |
4cbc57f0 JS |
210 | mpScrDc->DrawLine( scrRect.x, scrRect.y + 1, |
211 | scrRect.x, scrRect.y + scrRect.height ); | |
8e08b761 | 212 | |
4cbc57f0 JS |
213 | mpScrDc->DrawLine( scrRect.x+1, scrRect.y + scrRect.height, |
214 | scrRect.x + scrRect.width, scrRect.y + scrRect.height ); | |
8e08b761 | 215 | |
4cbc57f0 JS |
216 | mpScrDc->DrawLine( scrRect.x + scrRect.width , scrRect.y, |
217 | scrRect.x + scrRect.width, scrRect.y + scrRect.height + 1); | |
218 | } | |
8e08b761 | 219 | |
4cbc57f0 | 220 | mpScrDc->SetLogicalFunction( prevLF ); |
8e08b761 JS |
221 | } |
222 | ||
223 | void cbHintAnimationPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect) | |
224 | { | |
4cbc57f0 | 225 | DoDrawHintRect( rect, isInClientRect ); |
8e08b761 JS |
226 | } |
227 | ||
228 | void cbHintAnimationPlugin::EraseHintRect( wxRect& rect, bool isInClientRect) | |
229 | { | |
4cbc57f0 | 230 | DoDrawHintRect( rect, isInClientRect ); |
8e08b761 JS |
231 | } |
232 | ||
233 | void cbHintAnimationPlugin::FinishTracking() | |
234 | { | |
4cbc57f0 | 235 | wxScreenDC::EndDrawingOnTop(); |
8e08b761 | 236 | |
4cbc57f0 | 237 | delete mpScrDc; |
8e08b761 | 238 | |
4cbc57f0 | 239 | mpScrDc = NULL; |
8e08b761 JS |
240 | } |
241 | ||
242 | void cbHintAnimationPlugin::RectToScr( wxRect& frameRect, wxRect& scrRect ) | |
243 | { | |
4cbc57f0 | 244 | scrRect = frameRect; |
8e08b761 | 245 | |
4cbc57f0 | 246 | int x = frameRect.x, y = frameRect.y; |
8e08b761 | 247 | |
4cbc57f0 | 248 | mpLayout->GetParentFrame().ClientToScreen( &x, &y ); |
8e08b761 | 249 | |
4cbc57f0 JS |
250 | scrRect.x = x; |
251 | scrRect.y = y; | |
8e08b761 JS |
252 | } |
253 | ||
254 | /***** Implementation for class cbHintAnimTimer *****/ | |
255 | ||
256 | cbHintAnimTimer::cbHintAnimTimer(void) | |
257 | { | |
258 | #ifdef __WINDOWS__ | |
4cbc57f0 | 259 | mLock = 0L; |
8e08b761 JS |
260 | #endif |
261 | ||
4cbc57f0 | 262 | mPrevMorphed.x = POS_UNDEFINED; |
8e08b761 JS |
263 | } |
264 | ||
265 | void cbHintAnimTimer::MorphPoint( wxPoint& origin, MorphInfoT& info, wxPoint& point ) | |
266 | { | |
4cbc57f0 | 267 | // simulate lienar movement (FOR NOW:: without acceleration) |
8e08b761 | 268 | |
4cbc57f0 JS |
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 ); | |
8e08b761 | 277 | |
4cbc57f0 | 278 | point.x = int ( double ( info.mFrom.x + double (info.mTill.x - info.mFrom.x) * k ) ); |
8e08b761 | 279 | |
4cbc57f0 | 280 | point.y = int ( double ( info.mFrom.y + double (info.mTill.y - info.mFrom.y) * k ) ); |
8e08b761 | 281 | |
4cbc57f0 JS |
282 | point.x += origin.x; |
283 | point.y += origin.y; | |
8e08b761 JS |
284 | } |
285 | ||
286 | void cbHintAnimTimer::Notify(void) | |
287 | { | |
4cbc57f0 JS |
288 | // FIXME:: "clean" implementation should use mutex to sync |
289 | // between GUI and animation threads | |
8e08b761 | 290 | |
4cbc57f0 JS |
291 | if ( mpPl->mStopPending ) |
292 | { | |
293 | Stop(); // top timer | |
8e08b761 | 294 | |
4cbc57f0 | 295 | mpPl->FinishTracking(); |
8e08b761 | 296 | |
c82c42d4 | 297 | mpPl->mStopPending = false; |
4cbc57f0 | 298 | mpPl->mpAnimTimer = NULL; |
c82c42d4 | 299 | mpPl->mAnimStarted = false; |
8e08b761 | 300 | |
4cbc57f0 | 301 | mPrevMorphed.x = POS_UNDEFINED; |
8e08b761 | 302 | |
4cbc57f0 | 303 | delete this; |
8e08b761 | 304 | |
4cbc57f0 JS |
305 | return; |
306 | } | |
8e08b761 | 307 | |
4cbc57f0 | 308 | wxPoint origin( mpPl->mCurRect.x, mpPl->mCurRect.y ); |
8e08b761 | 309 | |
4cbc57f0 | 310 | wxPoint curUpper, curLower; |
8e08b761 | 311 | |
4cbc57f0 JS |
312 | MorphPoint( origin, mUpperLeft, curUpper ); |
313 | MorphPoint( origin, mLowerRight, curLower ); | |
8e08b761 | 314 | |
4cbc57f0 | 315 | if ( mPrevMorphed.x != POS_UNDEFINED ) |
8e08b761 | 316 | |
4cbc57f0 JS |
317 | // erase previous rect |
318 | mpPl->DoDrawHintRect( mPrevMorphed, mpPl->mPrevInClient ); | |
8e08b761 | 319 | |
4cbc57f0 JS |
320 | wxRect morphed( curUpper.x, curUpper.y, |
321 | curLower.x - curUpper.x, | |
322 | curLower.y - curUpper.y ); | |
8e08b761 | 323 | |
4cbc57f0 JS |
324 | // draw rect of current iteration |
325 | mpPl->DoDrawHintRect( morphed, | |
326 | ( mCurIter != mpPl->mMaxFrames - 1 ) | |
327 | ? mpPl->mPrevInClient : mpPl->mCurInClient ); | |
8e08b761 | 328 | |
4cbc57f0 | 329 | mPrevMorphed = morphed; |
8e08b761 | 330 | |
4cbc57f0 JS |
331 | if ( mCurIter == mpPl->mMaxFrames - 1 ) |
332 | { | |
333 | Stop(); // top timer | |
334 | ||
335 | mpPl->FinishTracking(); | |
336 | mpPl->mpAnimTimer = NULL; | |
c82c42d4 | 337 | mpPl->mAnimStarted = false; |
8e08b761 | 338 | |
4cbc57f0 | 339 | mPrevMorphed.x = POS_UNDEFINED; |
8e08b761 | 340 | |
4cbc57f0 JS |
341 | delete this; |
342 | } | |
343 | else | |
344 | ++mCurIter; | |
8e08b761 JS |
345 | } |
346 | ||
347 | bool cbHintAnimTimer::Init( cbHintAnimationPlugin* pAnimPl, bool reinit ) | |
348 | { | |
349 | ||
4cbc57f0 | 350 | mpPl = pAnimPl; |
8e08b761 | 351 | |
4cbc57f0 JS |
352 | // morph-points are set up relatively to the upper-left corner |
353 | // of the current hint-rectangle | |
8e08b761 | 354 | |
4cbc57f0 JS |
355 | if ( !reinit ) |
356 | { | |
357 | mUpperLeft.mFrom.x = mpPl->mPrevRect.x - mpPl->mCurRect.x; | |
358 | mUpperLeft.mFrom.y = mpPl->mPrevRect.y - mpPl->mCurRect.y; | |
8e08b761 | 359 | |
4cbc57f0 JS |
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 ); | |
8e08b761 | 366 | |
4cbc57f0 | 367 | wxPoint curUpper, curLower; |
8e08b761 | 368 | |
4cbc57f0 JS |
369 | MorphPoint( origin, mUpperLeft, curUpper ); |
370 | MorphPoint( origin, mLowerRight, curLower ); | |
8e08b761 | 371 | |
4cbc57f0 JS |
372 | mUpperLeft.mFrom.x = curUpper.x - mpPl->mCurRect.x; |
373 | mUpperLeft.mFrom.y = curUpper.y - mpPl->mCurRect.y; | |
8e08b761 | 374 | |
4cbc57f0 JS |
375 | mLowerRight.mFrom.x = ( mUpperLeft.mFrom.x + curLower.x - curUpper.x ); |
376 | mLowerRight.mFrom.y = ( mUpperLeft.mFrom.y + curLower.y - curUpper.y ); | |
377 | } | |
8e08b761 | 378 | |
4cbc57f0 JS |
379 | mUpperLeft.mTill.x = 0; |
380 | mUpperLeft.mTill.y = 0; | |
8e08b761 | 381 | |
4cbc57f0 JS |
382 | mLowerRight.mTill.x = mpPl->mCurRect.width; |
383 | mLowerRight.mTill.y = mpPl->mCurRect.height; | |
8e08b761 | 384 | |
4cbc57f0 JS |
385 | mCurIter = 1; |
386 | ||
387 | if ( !reinit ) | |
8e08b761 | 388 | |
4cbc57f0 | 389 | Start( mpPl->mMorphDelay ); |
8e08b761 | 390 | |
c82c42d4 | 391 | return true; |
8e08b761 JS |
392 | } |
393 |