]>
Commit | Line | Data |
---|---|---|
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$ | |
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 | ||
32 | IMPLEMENT_DYNAMIC_CLASS( cbHintAnimationPlugin, cbPluginBase ) | |
33 | ||
34 | BEGIN_EVENT_TABLE( cbHintAnimationPlugin, cbPluginBase ) | |
35 | ||
36 | EVT_PL_DRAW_HINT_RECT( cbHintAnimationPlugin::OnDrawHintRect ) | |
37 | ||
38 | END_EVENT_TABLE() | |
39 | ||
40 | cbHintAnimationPlugin::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 | ||
52 | cbHintAnimationPlugin::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 | ||
65 | cbHintAnimationPlugin::~cbHintAnimationPlugin() | |
66 | { | |
67 | if ( mpScrDc ) delete mpScrDc; | |
68 | } | |
69 | ||
70 | /*** rect-tracking related methods ***/ | |
71 | ||
72 | void 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 | ||
148 | static 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 | ||
154 | void cbHintAnimationPlugin::StartTracking() | |
155 | { | |
156 | mpScrDc = new wxScreenDC; | |
157 | ||
158 | wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame()); | |
159 | } | |
160 | ||
161 | void 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 | ||
223 | void cbHintAnimationPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect) | |
224 | { | |
225 | DoDrawHintRect( rect, isInClientRect ); | |
226 | } | |
227 | ||
228 | void cbHintAnimationPlugin::EraseHintRect( wxRect& rect, bool isInClientRect) | |
229 | { | |
230 | DoDrawHintRect( rect, isInClientRect ); | |
231 | } | |
232 | ||
233 | void cbHintAnimationPlugin::FinishTracking() | |
234 | { | |
235 | wxScreenDC::EndDrawingOnTop(); | |
236 | ||
237 | delete mpScrDc; | |
238 | ||
239 | mpScrDc = NULL; | |
240 | } | |
241 | ||
242 | void 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 | ||
256 | cbHintAnimTimer::cbHintAnimTimer(void) | |
257 | { | |
258 | #ifdef __WINDOWS__ | |
259 | mLock = 0L; | |
260 | #endif | |
261 | ||
262 | mPrevMorphed.x = POS_UNDEFINED; | |
263 | } | |
264 | ||
265 | void 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 | ||
286 | void 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 | ||
347 | bool 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 |