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