[CRT] spawn: define a unicode environment when needed
[reactos.git] / sdk / lib / 3rdparty / cardlib / cardrgnmouse.cpp
1 //
2 // CardLib - CardRegion mouse-related stuff
3 //
4 // Freeware
5 // Copyright J Brown 2001
6 //
7
8 #include "cardlib.h"
9
10 #include <math.h>
11
12 #if 1
13 #define TRACE(s)
14 #else
15 #define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
16 #endif
17
18 double __CARDZOOMSPEED = 32;
19
20 int ClipCard(HDC hdc, int x, int y, int width, int height);
21 void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height);
22
23 #ifdef _DEBUG
24
25 static pDebugClickProc DebugStackClickProc = 0;
26
27 void CardLib_SetStackClickProc(pDebugClickProc proc)
28 {
29 DebugStackClickProc = proc;
30 }
31
32 #endif
33
34 CardRegion *CardWindow::GetBestStack(int x, int y, int w, int h)
35 {
36 int maxoverlap = 0;
37 int maxoverlapidx = -1;
38
39 //find the stack which is most covered by the dropped
40 //cards. Only include those which allow drops.
41 //
42 for(int i = 0; i < nNumCardRegions; i++)
43 {
44 int percent = Regions[i]->GetOverlapRatio(x, y, w, h);
45
46 //if this stack has the biggest coverage yet
47 if(percent > maxoverlap && Regions[i]->IsVisible())
48 {
49 maxoverlap = percent;
50 maxoverlapidx = i;
51 }
52 }
53
54 //if we found a stack to drop onto
55 if(maxoverlapidx != -1)
56 {
57 return Regions[maxoverlapidx];
58 }
59 else
60 {
61 return 0;
62 }
63 }
64
65 bool CardRegion::IsPointInStack(int x, int y)
66 {
67 int axpos = xoffset < 0 ? xpos + (nNumApparentCards-1)*xoffset : xpos;
68 int aypos = yoffset < 0 ? ypos + (nNumApparentCards-1)*yoffset : ypos;
69
70 if(x >= axpos && x < axpos + width && y >= aypos && y < aypos + height && fVisible)
71 return true;
72 else
73 return false;
74 }
75
76 int CardRegion::GetNumDragCards(int x, int y)
77 {
78 int cardindex = 0; //index from stack start
79 int maxidx;
80
81 //make x,y relative to the stack's upper left corner
82 x -= xpos + (xoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * xoffset : 0);
83 y -= ypos + (yoffset < 0 ? (nNumApparentCards/*cardstack.NumCards()*/ - 1) * yoffset : 0);
84
85 //if stack is empty, cannot drag any cards from it
86 if(cardstack.NumCards() <= 0)
87 return 0;
88
89 //see which card in the stack has been clicked on
90 //top-bottom ordering
91 if(yoffset > 0)
92 {
93 if(y < height - __cardheight)
94 cardindex = y / yoffset;
95 else
96 cardindex = cardstack.NumCards() - 1;
97 }
98 else if(yoffset < 0)
99 {
100 if(y < __cardheight)
101 cardindex = cardstack.NumCards() - 1;
102 else
103 cardindex = cardstack.NumCards() - ((y - __cardheight) / -yoffset) - 2;
104 }
105 else //yoffset == 0
106 {
107 cardindex = cardstack.NumCards() - 1;
108 }
109
110 maxidx = cardindex;
111
112 //if left-right
113 if(xoffset > 0)
114 {
115 if(x < width - __cardwidth)
116 cardindex = x / xoffset;
117 else
118 cardindex = cardstack.NumCards() - 1;
119 }
120 else if(xoffset < 0)
121 {
122 if(x < __cardwidth)
123 cardindex = cardstack.NumCards() - 1;
124 else
125 cardindex = cardstack.NumCards() - ((x - __cardwidth) / -xoffset) - 2;
126 }
127 else
128 {
129 cardindex = cardstack.NumCards() - 1;
130 }
131
132 if(cardindex > maxidx) cardindex = maxidx;
133
134 if(cardindex > cardstack.NumCards())
135 cardindex = 1;
136
137 //if are trying to drag too many cards at once
138 return cardstack.NumCards() - cardindex;
139 }
140
141 bool CardRegion::CanDragCards(int iNumCards)
142 {
143 if(iNumCards <= 0) return false;
144 if(nThreedCount > 1 && iNumCards > 1) return false;
145
146 if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
147 {
148 // TRACE("Failed to gain access to card stack\n");
149 return false;
150 }
151
152 ReleaseMutex(mxlock);
153
154 switch(uDragRule)
155 {
156 case CS_DRAG_ALL:
157 return true;
158
159 case CS_DRAG_TOP:
160
161 if(iNumCards == 1)
162 return true;
163 else
164 return false;
165
166 case CS_DRAG_NONE:
167 return false;
168
169 case CS_DRAG_CALLBACK:
170
171 if(CanDragCallback)
172 {
173 return CanDragCallback(*this, iNumCards);
174 }
175 else
176 {
177 return false;
178 }
179
180 default:
181 return false;
182 }
183 }
184
185 bool CardRegion::CanDropCards(CardStack &cards)
186 {
187 if(WaitForSingleObject(mxlock, 0) != WAIT_OBJECT_0)
188 {
189 return false;
190 }
191
192 ReleaseMutex(mxlock);
193
194 switch(uDropRule)
195 {
196 case CS_DROP_ALL:
197 return true;
198
199 case CS_DROP_NONE:
200 return false;
201
202 case CS_DROP_CALLBACK:
203
204 if(CanDropCallback)
205 {
206 return CanDropCallback(*this, cards);
207 }
208 else
209 {
210 return false;
211 }
212
213 default:
214 return false;
215 }
216 }
217
218 bool CardRegion::OnLButtonDblClk(int x, int y)
219 {
220 iNumDragCards = GetNumDragCards(x, y);
221
222 if(DblClickCallback)
223 DblClickCallback(*this, iNumDragCards);
224
225 return true;
226 }
227
228 bool CardRegion::OnLButtonDown(int x, int y)
229 {
230 iNumDragCards = GetNumDragCards(x, y);
231
232 #ifdef _DEBUG
233 if(DebugStackClickProc)
234 {
235 if(!DebugStackClickProc(*this))
236 return false;
237 }
238 #endif
239
240 if(ClickCallback)
241 ClickCallback(*this, iNumDragCards);
242
243 if(CanDragCards(iNumDragCards) != false)
244 {
245
246 //offset of the mouse cursor relative to the top-left corner
247 //of the cards that are being dragged
248 mousexoffset = x - xpos - xoffset * (nNumApparentCards - iNumDragCards);
249 mouseyoffset = y - ypos - yoffset * (nNumApparentCards - iNumDragCards);
250
251 if(xoffset < 0)
252 mousexoffset += -xoffset * (iNumDragCards - 1);
253
254 if(yoffset < 0)
255 mouseyoffset += -yoffset * (iNumDragCards - 1);
256
257 //remove the cards from the source stack
258 dragstack = cardstack.Pop(iNumDragCards);
259
260 //prepare the back buffer, and the drag image
261 PrepareDragBitmaps(iNumDragCards);
262
263 oldx = x - mousexoffset;
264 oldy = y - mouseyoffset;
265
266 Update(); //Update this stack's card count + size
267
268 SetCapture((HWND)parentWnd);
269
270 //set AFTER settings the dragstack...
271 fMouseDragging = true;
272
273 return true;
274 }
275
276 return false;
277 }
278
279 void CardRegion::ClickRelease(int x, int y)
280 {
281 iNumDragCards = GetNumDragCards(x, y);
282
283 if (ClickReleaseCallback)
284 ClickReleaseCallback(*this, iNumDragCards);
285 }
286
287 bool CardRegion::OnLButtonUp(int x, int y)
288 {
289 CardRegion *pDestStack = 0;
290 HDC hdc;
291 int dropstackid = CS_DROPZONE_NODROP;
292
293 RECT dragrect;
294 DropZone *dropzone;
295
296 fMouseDragging = false;
297
298 //first of all, see if any drop zones have been registered
299 SetRect(&dragrect, x-mousexoffset, y-mouseyoffset, x-mousexoffset+nDragCardWidth, y-mouseyoffset+nDragCardHeight);
300
301 dropzone = parentWnd.GetDropZoneFromRect(&dragrect);
302
303 if(dropzone)
304 {
305 dropstackid = dropzone->DropCards(dragstack);
306
307 if(dropstackid != CS_DROPZONE_NODROP)
308 pDestStack = parentWnd.CardRegionFromId(dropstackid);
309 else
310 pDestStack = 0;
311 }
312 else
313 {
314 pDestStack = parentWnd.GetBestStack(x - mousexoffset, y - mouseyoffset, nDragCardWidth, nDragCardHeight);
315 }
316
317 // If have found a stack to drop onto
318 //
319 TRACE ( "can I drop card?\n" );
320 if(pDestStack && pDestStack->CanDropCards(dragstack))
321 {
322 TRACE ( "yes, dropping card\n" );
323 hdc = GetDC((HWND)parentWnd);
324 // UseNicePalette(hdc);
325 ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, pDestStack);
326 ReleaseDC((HWND)parentWnd, hdc);
327
328 //
329 //add the cards to the destination stack
330 //
331 CardStack temp = pDestStack->GetCardStack();
332 temp.Push(dragstack);
333
334 pDestStack->SetCardStack(temp);
335 // pDestStack->Update(); //Update this stack's card count + size
336 // pDestStack->UpdateFaceDir(temp);
337
338 // Call the remove callback on THIS stack, if one is specified
339 //
340 if(RemoveCallback)
341 RemoveCallback(*this, iNumDragCards);
342
343 // Call the add callback, if one is specified
344 //
345 if(pDestStack->AddCallback)
346 pDestStack->AddCallback(*pDestStack, pDestStack->cardstack);//index, deststack->numcards);
347
348 RedrawIfNotDim(pDestStack, true);
349 TRACE ( "done dropping card\n" );
350 }
351
352 //
353 // Otherwise, let the cards snap back onto this stack
354 //
355 else
356 {
357 TRACE ( "no, putting card back\n" );
358 hdc = GetDC((HWND)parentWnd);
359 TRACE ( "calling ZoomCard()\n" );
360 ZoomCard(hdc, x - mousexoffset, y - mouseyoffset, this);
361 TRACE ( "cardstack += dragstack\n" );
362 cardstack += dragstack;
363 TRACE ( "calling ReleaseDC()\n" );
364 ReleaseDC((HWND)parentWnd, hdc);
365
366 TRACE ( "calling Update()\n" );
367 Update(); //Update this stack's card count + size
368 TRACE ( "done putting card back\n" );
369 }
370
371 ReleaseDragBitmaps();
372 ReleaseCapture();
373
374 TRACE ( "OnLButtonUp() done\n" );
375 return true;
376 }
377
378 bool CardRegion::OnMouseMove(int x, int y)
379 {
380 HDC hdc;
381
382 hdc = GetDC((HWND)parentWnd);
383
384 x -= mousexoffset;
385 y -= mouseyoffset;
386
387 MoveDragCardTo(hdc, x, y);
388
389 //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
390 //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY);
391
392 ReleaseDC((HWND)parentWnd, hdc);
393
394 oldx = x;
395 oldy = y;
396
397 return true;
398 }
399
400 //
401 // There is a bug in BitBlt when the source x,y
402 // become < 0. So this wrapper function simply adjusts
403 // the coords so that we never try to blt in from this range
404 //
405 BOOL ClippedBitBlt(HDC hdcDest, int x, int y, int width, int height, HDC hdcSrc, int srcx, int srcy, DWORD dwROP)
406 {
407 if(srcx < 0)
408 {
409 x = 0 - srcx;
410 width = width + srcx;
411 srcx = 0;
412 }
413
414 if(srcy < 0)
415 {
416 y = 0 - srcy;
417 height = height + srcy;
418 srcy = 0;
419 }
420
421 return BitBlt(hdcDest, x, y, width, height, hdcSrc, srcx, srcy, dwROP);
422 }
423
424 void CardRegion::MoveDragCardTo(HDC hdc, int x, int y)
425 {
426 RECT inter, rect1, rect2;
427
428 //mask off the new position of the drag-card, so
429 //that it will not be painted over
430 ClipCard(hdc, x, y, nDragCardWidth, nDragCardHeight);
431
432 //restore the area covered by the card at its previous position
433 BitBlt(hdc, oldx, oldy, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
434
435 //remove clipping so we can draw the card at its new place
436 SelectClipRgn(hdc, NULL);
437
438 //if the card's old and new positions overlap, then we
439 //need some funky code to update the "saved background" image,
440 SetRect(&rect1, oldx, oldy, oldx+nDragCardWidth, oldy+nDragCardHeight);
441 SetRect(&rect2, x, y, x+nDragCardWidth, y+nDragCardHeight);
442
443 if(IntersectRect(&inter, &rect1, &rect2))
444 {
445 int interwidth = inter.right-inter.left;
446 int interheight = inter.bottom-inter.top;
447 int destx, desty, srcx, srcy;
448
449 if(rect2.left > rect1.left)
450 {
451 destx = 0; srcx = nDragCardWidth - interwidth;
452 }
453 else
454 {
455 destx = nDragCardWidth - interwidth; srcx = 0;
456 }
457
458 if(rect2.top > rect1.top)
459 {
460 desty = 0; srcy = nDragCardHeight - interheight;
461 }
462 else
463 {
464 desty = nDragCardHeight - interheight; srcy = 0;
465 }
466
467 //shift the bit we didn't use for the restore (due to the clipping)
468 //into the opposite corner
469 BitBlt(hdcBackGnd, destx,desty, interwidth, interheight, hdcBackGnd, srcx, srcy, SRCCOPY);
470
471 ExcludeClipRect(hdcBackGnd, destx, desty, destx+interwidth, desty+interheight);
472
473 //this bit requires us to clip the BitBlt (from screen to background)
474 //as BitBlt is a bit buggy it seems
475 ClippedBitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);
476 SelectClipRgn(hdcBackGnd, NULL);
477 }
478 else
479 {
480 BitBlt(hdcBackGnd, 0,0, nDragCardWidth, nDragCardHeight, hdc, x, y, SRCCOPY);
481 }
482
483 //finally draw the card to the screen
484 DrawCard(hdc, x, y, hdcDragCard, nDragCardWidth, nDragCardHeight);
485 }
486
487
488 //extern "C" int _fltused(void) { return 0; }
489 //extern "C" int _ftol(void) { return 0; }
490
491 //
492 // Better do this in fixed-point, to stop
493 // VC from linking in floatingpoint-long conversions
494 //
495 //#define FIXED_PREC_MOVE
496 #ifdef FIXED_PREC_MOVE
497 #define PRECISION 12
498 void ZoomCard(HDC hdc, int xpos, int ypos, CARDSTACK *dest)
499 {
500 long dx, dy, x , y;
501
502
503 int apparentcards;
504 x = xpos << PRECISION; y = ypos << PRECISION;
505
506 oldx = (int)xpos;
507 oldy = (int)ypos;
508
509 apparentcards=dest->numcards/dest->threedcount;
510
511 int idestx = dest->xpos + dest->xoffset * (apparentcards);// - iNumDragCards);
512 int idesty = dest->ypos + dest->yoffset * (apparentcards);// - iNumDragCards);
513
514 //normalise the motion vector
515 dx = (idestx<<PRECISION) - x;
516 dy = (idesty<<PRECISION) - y;
517 long recip = (1 << PRECISION) / 1;//sqrt(dx*dx + dy*dy);
518
519 dx *= recip * 16;//CARDZOOMSPEED;
520 dy *= recip * 16;//CARDZOOMSPEED;
521
522 //if(dx < 0) dxinc = 1.001; else
523
524 for(;;)
525 {
526 int ix, iy;
527 x += dx;
528 y += dy;
529
530 ix = (int)x>>PRECISION;
531 iy = (int)y>>PRECISION;
532 if(dx < 0 && ix < idestx) ix = idestx;
533 else if(dx > 0 && ix > idestx) ix = idestx;
534
535 if(dy < 0 && iy < idesty) iy = idesty;
536 else if(dy > 0 && iy > idesty) iy = idesty;
537
538 MoveDragCardTo(hdc, ix, iy);
539
540 if(ix == idestx && iy == idesty)
541 break;
542
543 oldx = (int)x >> PRECISION;
544 oldy = (int)y >> PRECISION;
545
546 //dx *= 1.2;
547 //dy *= 1.2;
548
549 Sleep(10);
550 }
551 }
552 #else
553 void CardRegion::ZoomCard(HDC hdc, int xpos, int ypos, CardRegion *pDestStack)
554 {
555 TRACE ( "ENTER ZoomCard()\n" );
556 double dx, dy, x ,y;
557 int apparentcards;
558 x = (double)xpos; y = (double)ypos;
559
560 oldx = (int)x;
561 oldy = (int)y;
562
563 apparentcards = pDestStack->cardstack.NumCards() / pDestStack->nThreedCount;
564
565 int idestx = pDestStack->xpos + pDestStack->xoffset * (apparentcards);
566 int idesty = pDestStack->ypos + pDestStack->yoffset * (apparentcards);
567
568 if(pDestStack->yoffset < 0)
569 idesty += pDestStack->yoffset * (iNumDragCards-1);
570
571 if(pDestStack->xoffset < 0)
572 idestx += pDestStack->xoffset * (iNumDragCards-1);
573
574 //normalise the motion vector
575 dx = idestx - x;
576 dy = idesty - y;
577 if ( fabs(dx) + fabs(dy) < 0.001f )
578 {
579 MoveDragCardTo(hdc, idestx, idesty);
580 return;
581 }
582 double recip = 1.0 / sqrt(dx*dx + dy*dy);
583 dx *= recip * __CARDZOOMSPEED; dy *= recip * __CARDZOOMSPEED;
584
585 //if(dx < 0) dxinc = 1.001; else
586
587 for(;;)
588 {
589 bool attarget = true;
590 int ix, iy;
591 x += dx;
592 y += dy;
593
594 ix = (int)x;
595 iy = (int)y;
596
597 if(dx < 0.0 && ix < idestx) ix = idestx;
598 else if(dx > 0.0 && ix > idestx) ix = idestx;
599 else attarget = false;
600
601 if(dy < 0.0 && iy < idesty) iy = idesty;
602 else if(dy > 0.0 && iy > idesty) iy = idesty;
603 else attarget = false;
604
605 //if the target stack wants the drag cards drawn differently
606 //to how they are, then redraw the drag card image just before
607 //the cards land
608 /*if(attarget == true)
609 {
610 for(int i = 0; i < iNumDragCards; i++)
611 {
612 int xdraw = pDestStack->xoffset*i;
613 int ydraw = pDestStack->yoffset*i;
614
615 if(pDestStack->yoffset < 0)
616 ydraw = -pDestStack->yoffset * (iNumDragCards-i-1);
617 if(pDestStack->xoffset < 0)
618 xdraw = -pDestStack->xoffset * (iNumDragCards-i-1);
619
620 if(pDestStack->facedirection == CS_FACEUP &&
621 pDestStack->numcards+i >= dest->numfacedown)
622 {
623 //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0);
624 }
625 else
626 {
627 //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0);
628 }
629 }
630 }*/
631
632 MoveDragCardTo(hdc, ix, iy);
633
634 if(attarget || (ix == idestx && iy == idesty))
635 break;
636
637 oldx = (int)x;
638 oldy = (int)y;
639
640 //dx *= 1.2;
641 //dy *= 1.2;
642
643 Sleep(10);
644 }
645 TRACE ( "EXIT ZoomCard()\n" );
646 }
647 #endif