1 /* -*- C++ -*-	Time-stamp: <08 May 99 15:05:38 Michael Bischoff>
2    XQtCardPile.cpp
3    This widget displays a pile of cards (slot, stack, etc...)
4    on the tableau widget
5  */
6 
7 #include "XQtCardPile.h"
8 #include "XQtCards.h"
9 #include "XQtTableau.h"
10 #include <qpainter.h>
11 #include <qpixmap.h>
12 #include <qbitmap.h>
13 #include <qevent.h>
14 #include "xpatgeo.h"
15 
sizeHint() const16 QSize XQtCardPile::sizeHint() const {
17     if (special_image != -1 && pileno >= 0 && pileno < game.numpiles) {
18 	struct pilegeometry *p = geo.pg + pileno;
19 	return QSize(p->w, p->h);
20     } else {
21 	if (geo.cw > 0 && geo.ch > 0)
22 	    return QSize(geo.cw, geo.ch);
23 	else
24 	    return QSize();
25     }
26 }
27 
mousePressEvent(QMouseEvent * e)28 void XQtCardPile::mousePressEvent(QMouseEvent* e) {
29     Cardindex c;
30     int mx = e->x(), my = e->y();
31     int cw = graphics->cardwidth(), ch = graphics->cardheight();
32     int button = 0;
33 //    printf("mouse is pressed in CardPile %d at %d,%d\n", pileno, mx, my);
34 
35     c = FindCardOfMousePos(pileno, mx, my);
36 
37     switch (e->button()) {
38     case LeftButton:
39 	if (c < 0)
40 	    return;
41 	button = 1;
42 	button_pressed(pileno, c, 1);	// quick move
43 	return;
44     case MidButton:
45 	button = 2;
46 	if (c == -2)
47 	    return;
48 	button_pressed(pileno, c, 2);	// select / deselect
49 	if (!tabl->dragndrop_on) {
50 	    return;			// done
51 	}
52 	c = game.srcind;		// reached card according to rules
53 	break;
54     case RightButton:
55 	if (c < 0)
56 	    return;
57 	button = 3;
58 	break;
59     default:
60 	return;
61     }
62 
63     if (c < 0)
64 	return;
65 //	printf("  pressed on card with value %d\n", game.cards[c]);
66     XQtCardPile *floating = new XQtCardPile(0, tabl);
67     int i, cx, cy, top;
68     struct pilegeometry *p = geo.pg + pileno;
69     i = c - INDEX_OF_FIRST_CARD(pileno);
70     if (e->button() == MidButton)
71 	// visible card = topmost card
72 	top = INDEX_OF_LAST_CARD(pileno);
73     else
74 	top = c;
75     cx = p->ox + i * p->cdx;
76     cy = p->oy + i * p->cdy;
77     floating->move(x() + cx, y() + cy);
78     floating->setMask(*(graphics->get_clipmap()));
79     if (game.visible[top])
80 	floating->special_image = game.cards[top];
81     else
82 	floating->special_image = 99;
83 
84     num_to_paint = -1;
85     if (e->button() == MidButton) {
86 	/* drag it */
87 	num_to_paint = c - INDEX_OF_FIRST_CARD(pileno);	// cards remaining to paint
88 	show_mark(0);
89 	repaint();
90 	tabl->startDrag(floating, mx - cx, my - cy, TRUE, cx + x(), cy + y(), pileno);
91     } else {
92 	/* only expose it */
93 	tabl->startDrag(floating, mx - cx, my - cy, FALSE, 0, 0, -1);
94     }
95 }
96 
97 /* the release event is sent to the widget which got the pressed event, not
98    to the widget where the mouse currently is over! */
mouseReleaseEvent(QMouseEvent * e)99 void XQtCardPile::mouseReleaseEvent(QMouseEvent* e) {
100 //    printf("Calling startAnimate(%d,%d)\n", special_image, pileno);
101 //    if (special_image >= 0) {
102 	// this is the dragged card
103 	// start movement with mouse coordinates
104 	tabl->startAnimate(x() + e->x(), y() + e->y());
105 //    }
106 }
107 
mouseMoveEvent(QMouseEvent * e)108 void XQtCardPile::mouseMoveEvent(QMouseEvent* e) {
109     tabl->Drag(x() + e->x(), y() + e->y());
110 }
111 
setCorrectSize()112 void XQtCardPile::setCorrectSize() {
113     struct pilegeometry *p;
114     p = geo.pg + pileno;
115     setGeometry(p->x, p->y, p->w, p->h);	// take values from geo.pg[]
116 }
117 
XQtCardPile(int pilenr,XQtTableau * parent,const char * name=0)118 XQtCardPile::XQtCardPile(int pilenr, XQtTableau *parent, const char *name=0)
119   : QWidget(parent, name) {
120     pileno = pilenr;
121     tabl = parent;
122     graphics = tabl->getCards();
123     num_to_paint = -1;
124     special_image = -1;
125     if (!NOT_DISPLAYED(geo.pg+pileno)) {
126 	setCorrectSize();
127 	setBackgroundColor(darkGreen);
128     }
129 //    fprintf(stderr, "created pile %d (type %d) at %d,%d, size %d,%d\n",
130 //	    pileno, game.piletype[pileno], x(), y(), width(), height());
131 
132 }
133 
compressCards()134 void XQtCardPile::compressCards() {
135     num_to_paint = -1;
136     if (pile_resize(pileno))
137 	repaint();
138 }
139 
paintEvent(QPaintEvent * event)140 void XQtCardPile::paintEvent(QPaintEvent *event) {
141     QPixmap *Pixmap_to_draw = 0;
142     int xdelta, ydelta, num;
143     struct pilegeometry *p = geo.pg + pileno;
144     xdelta = p->cdx;
145     ydelta = p->cdy;
146 
147     if (special_image != -1) {
148 	/* floating card */
149 	if (special_image == 99)
150 	    Pixmap_to_draw = graphics->get_pm_cardback();
151 	else
152 	    Pixmap_to_draw = graphics->get_pm_card(special_image);
153 	if (event)
154 	    bitBlt(this, event->rect().topLeft(), Pixmap_to_draw, event->rect());
155 	else
156 	    bitBlt(this, 0, 0, Pixmap_to_draw, graphics->cardwidth(), graphics->cardheight(), CopyROP, FALSE);
157 	return;
158     }
159     if (pileno < 0 || pileno >= game.numpiles) {
160 	printf("repaint request for pile %d (pos = %d,%d, size = %d,%d)\n",
161 	       pileno,
162 	       x(), y(), width(), height());
163 	return;
164     }
165     if (game.disable[pileno])     /* don't draw THIS pile */
166         return;
167     if (NOT_DISPLAYED(p))
168         return;                 /* draw nothing */
169 
170     num = num_to_paint < 0 ? CARDS_ON_PILE(pileno) : num_to_paint;
171 
172     if (!num) {          /* draw empty pile */
173         switch (game.piletype[pileno]) {
174         case Stack:
175 	    Pixmap_to_draw = graphics->get_pm_card(SUITSYMBOL + SUIT(pileno));
176             break;
177         default:
178             Pixmap_to_draw = graphics->get_pm_empty();
179             break;
180         }
181 	if (event)
182 	    bitBlt(this, event->rect().topLeft(), Pixmap_to_draw, event->rect());
183 	else
184 	    bitBlt(this, 0, 0, Pixmap_to_draw, graphics->cardwidth(), graphics->cardheight(), CopyROP, FALSE);
185     } else if (!ydelta && !xdelta) {      /* only topmost card is visible */
186         Cardindex c;
187         c = INDEX_OF_FIRST_CARD(pileno) + num - 1;
188 	Pixmap_to_draw = game.visible[c] ? graphics->get_pm_card(game.cards[c])
189 	 : graphics->get_pm_cardback();
190 
191 	if (event)
192 	    bitBlt(this, event->rect().topLeft(), Pixmap_to_draw, event->rect());
193 	else
194 	    bitBlt(this, 0, 0, Pixmap_to_draw, graphics->cardwidth(), graphics->cardheight(), CopyROP, FALSE);
195 
196     } else {
197 	// at least one card, painting a slot
198 	int cdelta = num;
199 	Cardindex c = INDEX_OF_FIRST_CARD(pileno) + num - cdelta; // the lowest one to repaint
200 	int i = c - INDEX_OF_FIRST_CARD(pileno);
201 
202 //	fprintf(stderr, "painting pile %d (%d cards, d=%d,%d)\n",
203 //		pileno, cdelta, xdelta, ydelta);
204 	while (--cdelta >= 0) {
205 	    int pw, ph;	// paint-width and height
206 //	    fprintf(stderr, "  visible=%d at %d,%d, size %d,%d\n", game.visible[c],
207 //		    xdelta*i, ydelta*i, graphics->cardwidth(), graphics->cardheight());
208 	    Pixmap_to_draw = game.visible[c] ? graphics->get_pm_card(game.cards[c])
209 		: graphics->get_pm_cardback();
210 	    pw = geo.cw;
211 	    ph = geo.ch;
212 	    if (cdelta) {
213 		/* Not the last card. May use card clipping optimisation */
214 		if (p->cdx == 0 && p->cdy > 0)
215 		    ph = p->cdy + geo.ry;
216 		if (p->cdy == 0 && p->cdx > 0)
217 		    pw = p->cdx + geo.rx;
218 	    }
219 	    bitBlt(this,
220 		   p->ox + p->cdx*i, p->oy + p->cdy*i,
221 		   Pixmap_to_draw, 0, 0,
222 		   pw, ph, CopyROP, FALSE);
223 	    ++c;
224 	    ++i;
225 	}
226     }
227 }
228