2 // CardLib - CardRegion mouse-related stuff
5 // Copyright J Brown 2001
15 #define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
18 double __CARDZOOMSPEED
= 32;
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
);
25 static pDebugClickProc DebugStackClickProc
= 0;
27 void CardLib_SetStackClickProc(pDebugClickProc proc
)
29 DebugStackClickProc
= proc
;
34 CardRegion
*CardWindow::GetBestStack(int x
, int y
, int w
, int h
)
37 int maxoverlapidx
= -1;
39 //find the stack which is most covered by the dropped
40 //cards. Only include those which allow drops.
42 for(int i
= 0; i
< nNumCardRegions
; i
++)
44 int percent
= Regions
[i
]->GetOverlapRatio(x
, y
, w
, h
);
46 //if this stack has the biggest coverage yet
47 if(percent
> maxoverlap
&& Regions
[i
]->IsVisible())
54 //if we found a stack to drop onto
55 if(maxoverlapidx
!= -1)
57 return Regions
[maxoverlapidx
];
65 bool CardRegion::IsPointInStack(int x
, int y
)
67 int axpos
= xoffset
< 0 ? xpos
+ (nNumApparentCards
-1)*xoffset
: xpos
;
68 int aypos
= yoffset
< 0 ? ypos
+ (nNumApparentCards
-1)*yoffset
: ypos
;
70 if(x
>= axpos
&& x
< axpos
+ width
&& y
>= aypos
&& y
< aypos
+ height
&& fVisible
)
76 int CardRegion::GetNumDragCards(int x
, int y
)
78 int cardindex
= 0; //index from stack start
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);
85 //if stack is empty, cannot drag any cards from it
86 if(cardstack
.NumCards() <= 0)
89 //see which card in the stack has been clicked on
93 if(y
< height
- __cardheight
)
94 cardindex
= y
/ yoffset
;
96 cardindex
= cardstack
.NumCards() - 1;
101 cardindex
= cardstack
.NumCards() - 1;
103 cardindex
= cardstack
.NumCards() - ((y
- __cardheight
) / -yoffset
) - 2;
107 cardindex
= cardstack
.NumCards() - 1;
115 if(x
< width
- __cardwidth
)
116 cardindex
= x
/ xoffset
;
118 cardindex
= cardstack
.NumCards() - 1;
123 cardindex
= cardstack
.NumCards() - 1;
125 cardindex
= cardstack
.NumCards() - ((x
- __cardwidth
) / -xoffset
) - 2;
129 cardindex
= cardstack
.NumCards() - 1;
132 if(cardindex
> maxidx
) cardindex
= maxidx
;
134 if(cardindex
> cardstack
.NumCards())
137 //if are trying to drag too many cards at once
138 return cardstack
.NumCards() - cardindex
;
141 bool CardRegion::CanDragCards(int iNumCards
)
143 if(iNumCards
<= 0) return false;
144 if(nThreedCount
> 1 && iNumCards
> 1) return false;
146 if(WaitForSingleObject(mxlock
, 0) != WAIT_OBJECT_0
)
148 // TRACE("Failed to gain access to card stack\n");
152 ReleaseMutex(mxlock
);
169 case CS_DRAG_CALLBACK
:
173 return CanDragCallback(*this, iNumCards
);
185 bool CardRegion::CanDropCards(CardStack
&cards
)
187 if(WaitForSingleObject(mxlock
, 0) != WAIT_OBJECT_0
)
192 ReleaseMutex(mxlock
);
202 case CS_DROP_CALLBACK
:
206 return CanDropCallback(*this, cards
);
218 bool CardRegion::OnLButtonDblClk(int x
, int y
)
220 iNumDragCards
= GetNumDragCards(x
, y
);
223 DblClickCallback(*this, iNumDragCards
);
228 bool CardRegion::OnLButtonDown(int x
, int y
)
230 iNumDragCards
= GetNumDragCards(x
, y
);
233 if(DebugStackClickProc
)
235 if(!DebugStackClickProc(*this))
241 ClickCallback(*this, iNumDragCards
);
243 if(CanDragCards(iNumDragCards
) != false)
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
);
252 mousexoffset
+= -xoffset
* (iNumDragCards
- 1);
255 mouseyoffset
+= -yoffset
* (iNumDragCards
- 1);
257 //remove the cards from the source stack
258 dragstack
= cardstack
.Pop(iNumDragCards
);
260 //prepare the back buffer, and the drag image
261 PrepareDragBitmaps(iNumDragCards
);
263 oldx
= x
- mousexoffset
;
264 oldy
= y
- mouseyoffset
;
266 Update(); //Update this stack's card count + size
268 SetCapture((HWND
)parentWnd
);
270 //set AFTER settings the dragstack...
271 fMouseDragging
= true;
279 void CardRegion::ClickRelease(int x
, int y
)
281 iNumDragCards
= GetNumDragCards(x
, y
);
283 if (ClickReleaseCallback
)
284 ClickReleaseCallback(*this, iNumDragCards
);
287 bool CardRegion::OnLButtonUp(int x
, int y
)
289 CardRegion
*pDestStack
= 0;
291 int dropstackid
= CS_DROPZONE_NODROP
;
296 fMouseDragging
= false;
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
);
301 dropzone
= parentWnd
.GetDropZoneFromRect(&dragrect
);
305 dropstackid
= dropzone
->DropCards(dragstack
);
307 if(dropstackid
!= CS_DROPZONE_NODROP
)
308 pDestStack
= parentWnd
.CardRegionFromId(dropstackid
);
314 pDestStack
= parentWnd
.GetBestStack(x
- mousexoffset
, y
- mouseyoffset
, nDragCardWidth
, nDragCardHeight
);
317 // If have found a stack to drop onto
319 TRACE ( "can I drop card?\n" );
320 if(pDestStack
&& pDestStack
->CanDropCards(dragstack
))
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
);
329 //add the cards to the destination stack
331 CardStack temp
= pDestStack
->GetCardStack();
332 temp
.Push(dragstack
);
334 pDestStack
->SetCardStack(temp
);
335 // pDestStack->Update(); //Update this stack's card count + size
336 // pDestStack->UpdateFaceDir(temp);
338 // Call the remove callback on THIS stack, if one is specified
341 RemoveCallback(*this, iNumDragCards
);
343 // Call the add callback, if one is specified
345 if(pDestStack
->AddCallback
)
346 pDestStack
->AddCallback(*pDestStack
, pDestStack
->cardstack
);//index, deststack->numcards);
348 RedrawIfNotDim(pDestStack
, true);
349 TRACE ( "done dropping card\n" );
353 // Otherwise, let the cards snap back onto this stack
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
);
366 TRACE ( "calling Update()\n" );
367 Update(); //Update this stack's card count + size
368 TRACE ( "done putting card back\n" );
371 ReleaseDragBitmaps();
374 TRACE ( "OnLButtonUp() done\n" );
378 bool CardRegion::OnMouseMove(int x
, int y
)
382 hdc
= GetDC((HWND
)parentWnd
);
387 MoveDragCardTo(hdc
, x
, y
);
389 //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
390 //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY);
392 ReleaseDC((HWND
)parentWnd
, hdc
);
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
405 BOOL
ClippedBitBlt(HDC hdcDest
, int x
, int y
, int width
, int height
, HDC hdcSrc
, int srcx
, int srcy
, DWORD dwROP
)
410 width
= width
+ srcx
;
417 height
= height
+ srcy
;
421 return BitBlt(hdcDest
, x
, y
, width
, height
, hdcSrc
, srcx
, srcy
, dwROP
);
424 void CardRegion::MoveDragCardTo(HDC hdc
, int x
, int y
)
426 RECT inter
, rect1
, rect2
;
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
);
432 //restore the area covered by the card at its previous position
433 BitBlt(hdc
, oldx
, oldy
, nDragCardWidth
, nDragCardHeight
, hdcBackGnd
, 0, 0, SRCCOPY
);
435 //remove clipping so we can draw the card at its new place
436 SelectClipRgn(hdc
, NULL
);
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
);
443 if(IntersectRect(&inter
, &rect1
, &rect2
))
445 int interwidth
= inter
.right
-inter
.left
;
446 int interheight
= inter
.bottom
-inter
.top
;
447 int destx
, desty
, srcx
, srcy
;
449 if(rect2
.left
> rect1
.left
)
451 destx
= 0; srcx
= nDragCardWidth
- interwidth
;
455 destx
= nDragCardWidth
- interwidth
; srcx
= 0;
458 if(rect2
.top
> rect1
.top
)
460 desty
= 0; srcy
= nDragCardHeight
- interheight
;
464 desty
= nDragCardHeight
- interheight
; srcy
= 0;
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
);
471 ExcludeClipRect(hdcBackGnd
, destx
, desty
, destx
+interwidth
, desty
+interheight
);
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
);
480 BitBlt(hdcBackGnd
, 0,0, nDragCardWidth
, nDragCardHeight
, hdc
, x
, y
, SRCCOPY
);
483 //finally draw the card to the screen
484 DrawCard(hdc
, x
, y
, hdcDragCard
, nDragCardWidth
, nDragCardHeight
);
488 //extern "C" int _fltused(void) { return 0; }
489 //extern "C" int _ftol(void) { return 0; }
492 // Better do this in fixed-point, to stop
493 // VC from linking in floatingpoint-long conversions
495 //#define FIXED_PREC_MOVE
496 #ifdef FIXED_PREC_MOVE
498 void ZoomCard(HDC hdc
, int xpos
, int ypos
, CARDSTACK
*dest
)
504 x
= xpos
<< PRECISION
; y
= ypos
<< PRECISION
;
509 apparentcards
=dest
->numcards
/dest
->threedcount
;
511 int idestx
= dest
->xpos
+ dest
->xoffset
* (apparentcards
);// - iNumDragCards);
512 int idesty
= dest
->ypos
+ dest
->yoffset
* (apparentcards
);// - iNumDragCards);
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);
519 dx
*= recip
* 16;//CARDZOOMSPEED;
520 dy
*= recip
* 16;//CARDZOOMSPEED;
522 //if(dx < 0) dxinc = 1.001; else
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
;
535 if(dy
< 0 && iy
< idesty
) iy
= idesty
;
536 else if(dy
> 0 && iy
> idesty
) iy
= idesty
;
538 MoveDragCardTo(hdc
, ix
, iy
);
540 if(ix
== idestx
&& iy
== idesty
)
543 oldx
= (int)x
>> PRECISION
;
544 oldy
= (int)y
>> PRECISION
;
553 void CardRegion::ZoomCard(HDC hdc
, int xpos
, int ypos
, CardRegion
*pDestStack
)
555 TRACE ( "ENTER ZoomCard()\n" );
558 x
= (double)xpos
; y
= (double)ypos
;
563 apparentcards
= pDestStack
->cardstack
.NumCards() / pDestStack
->nThreedCount
;
565 int idestx
= pDestStack
->xpos
+ pDestStack
->xoffset
* (apparentcards
);
566 int idesty
= pDestStack
->ypos
+ pDestStack
->yoffset
* (apparentcards
);
568 if(pDestStack
->yoffset
< 0)
569 idesty
+= pDestStack
->yoffset
* (iNumDragCards
-1);
571 if(pDestStack
->xoffset
< 0)
572 idestx
+= pDestStack
->xoffset
* (iNumDragCards
-1);
574 //normalise the motion vector
577 if ( fabs(dx
) + fabs(dy
) < 0.001f
)
579 MoveDragCardTo(hdc
, idestx
, idesty
);
582 double recip
= 1.0 / sqrt(dx
*dx
+ dy
*dy
);
583 dx
*= recip
* __CARDZOOMSPEED
; dy
*= recip
* __CARDZOOMSPEED
;
585 //if(dx < 0) dxinc = 1.001; else
589 bool attarget
= true;
597 if(dx
< 0.0 && ix
< idestx
) ix
= idestx
;
598 else if(dx
> 0.0 && ix
> idestx
) ix
= idestx
;
599 else attarget
= false;
601 if(dy
< 0.0 && iy
< idesty
) iy
= idesty
;
602 else if(dy
> 0.0 && iy
> idesty
) iy
= idesty
;
603 else attarget
= false;
605 //if the target stack wants the drag cards drawn differently
606 //to how they are, then redraw the drag card image just before
608 /*if(attarget == true)
610 for(int i = 0; i < iNumDragCards; i++)
612 int xdraw = pDestStack->xoffset*i;
613 int ydraw = pDestStack->yoffset*i;
615 if(pDestStack->yoffset < 0)
616 ydraw = -pDestStack->yoffset * (iNumDragCards-i-1);
617 if(pDestStack->xoffset < 0)
618 xdraw = -pDestStack->xoffset * (iNumDragCards-i-1);
620 if(pDestStack->facedirection == CS_FACEUP &&
621 pDestStack->numcards+i >= dest->numfacedown)
623 //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0);
627 //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0);
632 MoveDragCardTo(hdc
, ix
, iy
);
634 if(attarget
|| (ix
== idestx
&& iy
== idesty
))
645 TRACE ( "EXIT ZoomCard()\n" );