2 // CardLib - CardRegion mouse-related stuff
5 // Copyright J Brown 2001
12 #include "cardwindow.h"
13 #include "cardregion.h"
18 #define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
21 double __CARDZOOMSPEED
= 32;
23 int ClipCard(HDC hdc
, int x
, int y
, int width
, int height
);
24 void DrawCard(HDC hdc
, int x
, int y
, HDC hdcSource
, int width
, int height
);
28 static pDebugClickProc DebugStackClickProc
= 0;
30 void CardLib_SetStackClickProc(pDebugClickProc proc
)
32 DebugStackClickProc
= proc
;
37 CardRegion
*CardWindow::GetBestStack(int x
, int y
, int w
, int h
)
40 int maxoverlapidx
= -1;
42 //find the stack which is most covered by the dropped
43 //cards. Only include those which allow drops.
45 for(int i
= 0; i
< nNumCardRegions
; i
++)
47 int percent
= Regions
[i
]->GetOverlapRatio(x
, y
, w
, h
);
49 //if this stack has the biggest coverage yet
50 if(percent
> maxoverlap
&& Regions
[i
]->IsVisible())
57 //if we found a stack to drop onto
58 if(maxoverlapidx
!= -1)
60 return Regions
[maxoverlapidx
];
68 bool CardRegion::IsPointInStack(int x
, int y
)
70 int axpos
= xoffset
< 0 ? xpos
+ (nNumApparentCards
-1)*xoffset
: xpos
;
71 int aypos
= yoffset
< 0 ? ypos
+ (nNumApparentCards
-1)*yoffset
: ypos
;
73 if(x
>= axpos
&& x
< axpos
+ width
&& y
>= aypos
&& y
< aypos
+ height
&& fVisible
)
79 int CardRegion::GetNumDragCards(int x
, int y
)
81 int cardindex
= 0; //index from stack start
84 //make x,y relative to the stack's upper left corner
85 x
-= xpos
+ (xoffset
< 0 ? (nNumApparentCards
/*cardstack.NumCards()*/ - 1) * xoffset
: 0);
86 y
-= ypos
+ (yoffset
< 0 ? (nNumApparentCards
/*cardstack.NumCards()*/ - 1) * yoffset
: 0);
88 //if stack is empty, cannot drag any cards from it
89 if(cardstack
.NumCards() <= 0)
92 //see which card in the stack has been clicked on
96 if(y
< height
- __cardheight
)
97 cardindex
= y
/ yoffset
;
99 cardindex
= cardstack
.NumCards() - 1;
104 cardindex
= cardstack
.NumCards() - 1;
106 cardindex
= cardstack
.NumCards() - ((y
- __cardheight
) / -yoffset
) - 2;
110 cardindex
= cardstack
.NumCards() - 1;
118 if(x
< width
- __cardwidth
)
119 cardindex
= x
/ xoffset
;
121 cardindex
= cardstack
.NumCards() - 1;
126 cardindex
= cardstack
.NumCards() - 1;
128 cardindex
= cardstack
.NumCards() - ((x
- __cardwidth
) / -xoffset
) - 2;
132 cardindex
= cardstack
.NumCards() - 1;
135 if(cardindex
> maxidx
) cardindex
= maxidx
;
137 if(cardindex
> cardstack
.NumCards())
140 //if are trying to drag too many cards at once
141 return cardstack
.NumCards() - cardindex
;
144 bool CardRegion::CanDragCards(int iNumCards
)
146 if(iNumCards
<= 0) return false;
147 if(nThreedCount
> 1 && iNumCards
> 1) return false;
149 if(WaitForSingleObject(mxlock
, 0) != WAIT_OBJECT_0
)
151 // TRACE("Failed to gain access to card stack\n");
155 ReleaseMutex(mxlock
);
172 case CS_DRAG_CALLBACK
:
176 return CanDragCallback(*this, iNumCards
);
188 bool CardRegion::CanDropCards(CardStack
&cards
)
190 if(WaitForSingleObject(mxlock
, 0) != WAIT_OBJECT_0
)
195 ReleaseMutex(mxlock
);
205 case CS_DROP_CALLBACK
:
209 return CanDropCallback(*this, cards
);
221 bool CardRegion::OnLButtonDblClk(int x
, int y
)
223 iNumDragCards
= GetNumDragCards(x
, y
);
226 DblClickCallback(*this, iNumDragCards
);
231 bool CardRegion::OnLButtonDown(int x
, int y
)
233 iNumDragCards
= GetNumDragCards(x
, y
);
236 if(DebugStackClickProc
)
238 if(!DebugStackClickProc(*this))
244 ClickCallback(*this, iNumDragCards
);
246 if(CanDragCards(iNumDragCards
) != false)
249 //offset of the mouse cursor relative to the top-left corner
250 //of the cards that are being dragged
251 mousexoffset
= x
- xpos
- xoffset
* (nNumApparentCards
- iNumDragCards
);
252 mouseyoffset
= y
- ypos
- yoffset
* (nNumApparentCards
- iNumDragCards
);
255 mousexoffset
+= -xoffset
* (iNumDragCards
- 1);
258 mouseyoffset
+= -yoffset
* (iNumDragCards
- 1);
260 //remove the cards from the source stack
261 dragstack
= cardstack
.Pop(iNumDragCards
);
263 //prepare the back buffer, and the drag image
264 PrepareDragBitmaps(iNumDragCards
);
266 oldx
= x
- mousexoffset
;
267 oldy
= y
- mouseyoffset
;
269 Update(); //Update this stack's card count + size
271 SetCapture((HWND
)parentWnd
);
273 //set AFTER settings the dragstack...
274 fMouseDragging
= true;
282 bool CardRegion::OnLButtonUp(int x
, int y
)
284 CardRegion
*pDestStack
= 0;
286 int dropstackid
= CS_DROPZONE_NODROP
;
291 fMouseDragging
= false;
293 //first of all, see if any drop zones have been registered
294 SetRect(&dragrect
, x
-mousexoffset
, y
-mouseyoffset
, x
-mousexoffset
+nDragCardWidth
, y
-mouseyoffset
+nDragCardHeight
);
296 dropzone
= parentWnd
.GetDropZoneFromRect(&dragrect
);
300 dropstackid
= dropzone
->DropCards(dragstack
);
302 if(dropstackid
!= CS_DROPZONE_NODROP
)
303 pDestStack
= parentWnd
.CardRegionFromId(dropstackid
);
309 pDestStack
= parentWnd
.GetBestStack(x
- mousexoffset
, y
- mouseyoffset
, nDragCardWidth
, nDragCardHeight
);
312 // If have found a stack to drop onto
314 TRACE ( "can I drop card?\n" );
315 if(pDestStack
&& pDestStack
->CanDropCards(dragstack
))
317 TRACE ( "yes, dropping card\n" );
318 hdc
= GetDC((HWND
)parentWnd
);
319 // UseNicePalette(hdc);
320 ZoomCard(hdc
, x
- mousexoffset
, y
- mouseyoffset
, pDestStack
);
321 ReleaseDC((HWND
)parentWnd
, hdc
);
324 //add the cards to the destination stack
326 CardStack temp
= pDestStack
->GetCardStack();
327 temp
.Push(dragstack
);
329 pDestStack
->SetCardStack(temp
);
330 // pDestStack->Update(); //Update this stack's card count + size
331 // pDestStack->UpdateFaceDir(temp);
333 // Call the remove callback on THIS stack, if one is specified
336 RemoveCallback(*this, iNumDragCards
);
338 // Call the add callback, if one is specified
340 if(pDestStack
->AddCallback
)
341 pDestStack
->AddCallback(*pDestStack
, pDestStack
->cardstack
);//index, deststack->numcards);
343 RedrawIfNotDim(pDestStack
, true);
344 TRACE ( "done dropping card\n" );
348 // Otherwise, let the cards snap back onto this stack
352 TRACE ( "no, putting card back\n" );
353 hdc
= GetDC((HWND
)parentWnd
);
354 TRACE ( "calling ZoomCard()\n" );
355 ZoomCard(hdc
, x
- mousexoffset
, y
- mouseyoffset
, this);
356 TRACE ( "cardstack += dragstack\n" );
357 cardstack
+= dragstack
;
358 TRACE ( "calling ReleaseDC()\n" );
359 ReleaseDC((HWND
)parentWnd
, hdc
);
361 TRACE ( "calling Update()\n" );
362 Update(); //Update this stack's card count + size
363 TRACE ( "done putting card back\n" );
366 ReleaseDragBitmaps();
369 TRACE ( "OnLButtonUp() done\n" );
373 bool CardRegion::OnMouseMove(int x
, int y
)
377 hdc
= GetDC((HWND
)parentWnd
);
382 MoveDragCardTo(hdc
, x
, y
);
384 //BitBlt(hdc, nDragCardWidth+10, 0, nDragCardWidth, nDragCardHeight, hdcBackGnd, 0, 0, SRCCOPY);
385 //BitBlt(hdc, 0, 0, nDragCardWidth, nDragCardHeight, hdcDragCard, 0, 0, SRCCOPY);
387 ReleaseDC((HWND
)parentWnd
, hdc
);
396 // There is a bug in BitBlt when the source x,y
397 // become < 0. So this wrapper function simply adjusts
398 // the coords so that we never try to blt in from this range
400 BOOL
ClippedBitBlt(HDC hdcDest
, int x
, int y
, int width
, int height
, HDC hdcSrc
, int srcx
, int srcy
, DWORD dwROP
)
405 width
= width
+ srcx
;
412 height
= height
+ srcy
;
416 return BitBlt(hdcDest
, x
, y
, width
, height
, hdcSrc
, srcx
, srcy
, dwROP
);
419 void CardRegion::MoveDragCardTo(HDC hdc
, int x
, int y
)
421 RECT inter
, rect1
, rect2
;
423 //mask off the new position of the drag-card, so
424 //that it will not be painted over
425 ClipCard(hdc
, x
, y
, nDragCardWidth
, nDragCardHeight
);
427 //restore the area covered by the card at its previous position
428 BitBlt(hdc
, oldx
, oldy
, nDragCardWidth
, nDragCardHeight
, hdcBackGnd
, 0, 0, SRCCOPY
);
430 //remove clipping so we can draw the card at its new place
431 SelectClipRgn(hdc
, NULL
);
433 //if the card's old and new positions overlap, then we
434 //need some funky code to update the "saved background" image,
435 SetRect(&rect1
, oldx
, oldy
, oldx
+nDragCardWidth
, oldy
+nDragCardHeight
);
436 SetRect(&rect2
, x
, y
, x
+nDragCardWidth
, y
+nDragCardHeight
);
438 if(IntersectRect(&inter
, &rect1
, &rect2
))
440 int interwidth
= inter
.right
-inter
.left
;
441 int interheight
= inter
.bottom
-inter
.top
;
442 int destx
, desty
, srcx
, srcy
;
444 if(rect2
.left
> rect1
.left
)
446 destx
= 0; srcx
= nDragCardWidth
- interwidth
;
450 destx
= nDragCardWidth
- interwidth
; srcx
= 0;
453 if(rect2
.top
> rect1
.top
)
455 desty
= 0; srcy
= nDragCardHeight
- interheight
;
459 desty
= nDragCardHeight
- interheight
; srcy
= 0;
462 //shift the bit we didn't use for the restore (due to the clipping)
463 //into the opposite corner
464 BitBlt(hdcBackGnd
, destx
,desty
, interwidth
, interheight
, hdcBackGnd
, srcx
, srcy
, SRCCOPY
);
466 ExcludeClipRect(hdcBackGnd
, destx
, desty
, destx
+interwidth
, desty
+interheight
);
468 //this bit requires us to clip the BitBlt (from screen to background)
469 //as BitBlt is a bit buggy it seems
470 ClippedBitBlt(hdcBackGnd
, 0,0, nDragCardWidth
, nDragCardHeight
, hdc
, x
, y
, SRCCOPY
);
471 SelectClipRgn(hdcBackGnd
, NULL
);
475 BitBlt(hdcBackGnd
, 0,0, nDragCardWidth
, nDragCardHeight
, hdc
, x
, y
, SRCCOPY
);
478 //finally draw the card to the screen
479 DrawCard(hdc
, x
, y
, hdcDragCard
, nDragCardWidth
, nDragCardHeight
);
483 //extern "C" int _fltused(void) { return 0; }
484 //extern "C" int _ftol(void) { return 0; }
487 // Better do this in fixed-point, to stop
488 // VC from linking in floatingpoint-long conversions
490 //#define FIXED_PREC_MOVE
491 #ifdef FIXED_PREC_MOVE
493 void ZoomCard(HDC hdc
, int xpos
, int ypos
, CARDSTACK
*dest
)
499 x
= xpos
<< PRECISION
; y
= ypos
<< PRECISION
;
504 apparentcards
=dest
->numcards
/dest
->threedcount
;
506 int idestx
= dest
->xpos
+ dest
->xoffset
* (apparentcards
);// - iNumDragCards);
507 int idesty
= dest
->ypos
+ dest
->yoffset
* (apparentcards
);// - iNumDragCards);
509 //normalise the motion vector
510 dx
= (idestx
<<PRECISION
) - x
;
511 dy
= (idesty
<<PRECISION
) - y
;
512 long recip
= (1 << PRECISION
) / 1;//sqrt(dx*dx + dy*dy);
514 dx
*= recip
* 16;//CARDZOOMSPEED;
515 dy
*= recip
* 16;//CARDZOOMSPEED;
517 //if(dx < 0) dxinc = 1.001; else
525 ix
= (int)x
>>PRECISION
;
526 iy
= (int)y
>>PRECISION
;
527 if(dx
< 0 && ix
< idestx
) ix
= idestx
;
528 else if(dx
> 0 && ix
> idestx
) ix
= idestx
;
530 if(dy
< 0 && iy
< idesty
) iy
= idesty
;
531 else if(dy
> 0 && iy
> idesty
) iy
= idesty
;
533 MoveDragCardTo(hdc
, ix
, iy
);
535 if(ix
== idestx
&& iy
== idesty
)
538 oldx
= (int)x
>> PRECISION
;
539 oldy
= (int)y
>> PRECISION
;
548 void CardRegion::ZoomCard(HDC hdc
, int xpos
, int ypos
, CardRegion
*pDestStack
)
550 TRACE ( "ENTER ZoomCard()\n" );
553 x
= (double)xpos
; y
= (double)ypos
;
558 apparentcards
= pDestStack
->cardstack
.NumCards() / pDestStack
->nThreedCount
;
560 int idestx
= pDestStack
->xpos
+ pDestStack
->xoffset
* (apparentcards
);
561 int idesty
= pDestStack
->ypos
+ pDestStack
->yoffset
* (apparentcards
);
563 if(pDestStack
->yoffset
< 0)
564 idesty
+= pDestStack
->yoffset
* (iNumDragCards
-1);
566 if(pDestStack
->xoffset
< 0)
567 idestx
+= pDestStack
->xoffset
* (iNumDragCards
-1);
569 //normalise the motion vector
572 if ( fabs(dx
) + fabs(dy
) < 0.001f
)
574 MoveDragCardTo(hdc
, idestx
, idesty
);
577 double recip
= 1.0 / sqrt(dx
*dx
+ dy
*dy
);
578 dx
*= recip
* __CARDZOOMSPEED
; dy
*= recip
* __CARDZOOMSPEED
;
580 //if(dx < 0) dxinc = 1.001; else
584 bool attarget
= true;
592 if(dx
< 0.0 && ix
< idestx
) ix
= idestx
;
593 else if(dx
> 0.0 && ix
> idestx
) ix
= idestx
;
594 else attarget
= false;
596 if(dy
< 0.0 && iy
< idesty
) iy
= idesty
;
597 else if(dy
> 0.0 && iy
> idesty
) iy
= idesty
;
598 else attarget
= false;
600 //if the target stack wants the drag cards drawn differently
601 //to how they are, then redraw the drag card image just before
603 /*if(attarget == true)
605 for(int i = 0; i < iNumDragCards; i++)
607 int xdraw = pDestStack->xoffset*i;
608 int ydraw = pDestStack->yoffset*i;
610 if(pDestStack->yoffset < 0)
611 ydraw = -pDestStack->yoffset * (iNumDragCards-i-1);
612 if(pDestStack->xoffset < 0)
613 xdraw = -pDestStack->xoffset * (iNumDragCards-i-1);
615 if(pDestStack->facedirection == CS_FACEUP &&
616 pDestStack->numcards+i >= dest->numfacedown)
618 //cdtDraw(hdcDragCard, xdraw, ydraw, iDragCards[i], ectFACES, 0);
622 //cdtDraw(hdcDragCard, xdraw, ydraw, CARDSTACK::backcard, ectBACKS, 0);
627 MoveDragCardTo(hdc
, ix
, iy
);
629 if(attarget
|| ix
== idestx
&& iy
== idesty
)
640 TRACE ( "EXIT ZoomCard()\n" );