2 * draw.c -- drawing routines for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
56 #include <cairo/cairo.h>
57 #include <cairo/cairo-xlib.h>
62 #else /* not STDC_HEADERS */
63 extern char *getenv();
66 # else /* not HAVE_STRING_H */
68 # endif /* not HAVE_STRING_H */
69 #endif /* not STDC_HEADERS */
76 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
80 #include "pixmaps/pixmaps.h"
82 #include "bitmaps/bitmaps.h"
87 #include "xevalgraph.h"
99 #define usleep(t) _sleep2(((t)+500)/1000)
103 # define _(s) gettext (s)
104 # define N_(s) gettext_noop (s)
112 Boolean cairoAnimate;
113 static cairo_surface_t *csBoardWindow, *csBoardBackup, *csDualBoard;
114 static cairo_surface_t *pngPieceBitmaps[2][(int)BlackPawn]; // scaled pieces as used
115 static cairo_surface_t *pngPieceBitmaps2[2][(int)BlackPawn+4]; // scaled pieces in store
116 static cairo_surface_t *pngBoardBitmap[2];
117 int useTexture, textureW[2], textureH[2];
119 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
120 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
122 #define White(piece) ((int)(piece) < (int)BlackPawn)
126 } gridSegments[BOARD_RANKS + BOARD_FILES + 2];
133 cairo_surface_t *cstmp = csBoardWindow;
134 csBoardWindow = csDualBoard;
137 csBoardWindow = GetOutputSurface(&dualOptions[3], 0, 0);
146 // delete surfaces after size becomes invalid, so they will be recreated
147 if(csBoardWindow) cairo_surface_destroy(csBoardWindow);
148 if(csBoardBackup) cairo_surface_destroy(csBoardBackup);
149 if(csDualBoard) cairo_surface_destroy(csDualBoard);
150 csBoardWindow = csBoardBackup = csDualBoard = NULL;
153 #define BoardSize int
155 InitDrawingSizes (BoardSize boardSize, int flags)
156 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
157 int boardWidth, boardHeight;
159 static int oldWidth, oldHeight;
160 static VariantClass oldVariant;
161 static int oldMono = -1, oldTwoBoards = 0;
162 extern Widget formWidget;
164 if(!formWidget) return;
166 if(oldTwoBoards && !twoBoards) PopDown(DummyDlg);
167 oldTwoBoards = twoBoards;
169 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
170 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
171 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
173 if(boardWidth != oldWidth || boardHeight != oldHeight) { // do resizing stuff only if size actually changed
175 oldWidth = boardWidth; oldHeight = boardHeight;
180 * Inhibit shell resizing.
182 ResizeBoardWindow(boardWidth, boardHeight, 0);
187 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
190 if(gameInfo.variant != oldVariant) { // and only if variant changed
194 for(p=0; p<=(int)WhiteKing; p++)
195 pngPieceBitmaps[i][p] = pngPieceBitmaps2[i][p]; // defaults
196 if(gameInfo.variant == VariantShogi) {
197 pngPieceBitmaps[i][(int)WhiteCannon] = pngPieceBitmaps2[i][(int)WhiteKing+1];
198 pngPieceBitmaps[i][(int)WhiteNightrider] = pngPieceBitmaps2[i][(int)WhiteKing+2];
199 pngPieceBitmaps[i][(int)WhiteSilver] = pngPieceBitmaps2[i][(int)WhiteKing+3];
200 pngPieceBitmaps[i][(int)WhiteGrasshopper] = pngPieceBitmaps2[i][(int)WhiteKing+4];
201 pngPieceBitmaps[i][(int)WhiteQueen] = pngPieceBitmaps2[i][(int)WhiteLance];
204 if(gameInfo.variant == VariantGothic) {
205 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteSilver];
208 if(gameInfo.variant == VariantSChess) {
209 pngPieceBitmaps[i][(int)WhiteAngel] = pngPieceBitmaps2[i][(int)WhiteFalcon];
210 pngPieceBitmaps[i][(int)WhiteMarshall] = pngPieceBitmaps2[i][(int)WhiteAlfil];
213 oldMono = -10; // kludge to force recreation of animation masks
214 oldVariant = gameInfo.variant;
217 oldMono = appData.monoMode;
221 CreatePNGBoard (char *s, int kind)
223 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
224 if(strstr(s, ".png")) {
225 cairo_surface_t *img = cairo_image_surface_create_from_png (s);
227 useTexture |= kind + 1; pngBoardBitmap[kind] = img;
228 textureW[kind] = cairo_image_surface_get_width (img);
229 textureH[kind] = cairo_image_surface_get_height (img);
234 char *pngPieceNames[] = // must be in same order as internal piece encoding
235 { "Pawn", "Knight", "Bishop", "Rook", "Queen", "Advisor", "Elephant", "Archbishop", "Marshall", "Gold", "Commoner",
236 "Canon", "Nightrider", "CrownedBishop", "CrownedRook", "Princess", "Chancellor", "Hawk", "Lance", "Cobra", "Unicorn", "King",
237 "GoldKnight", "GoldLance", "GoldPawn", "GoldSilver", NULL
241 ConvertPixmap (int color, int piece)
243 int i, j, stride, f, colcode[10], w, b;
245 cairo_surface_t *res;
246 XpmPieces *p = builtInXpms + 10;
247 char **pixels = p->xpm[piece % BlackPawn][2*color];
249 sscanf(pixels[0], "%*d %*d %d", &f);
250 sscanf(appData.whitePieceColor+1, "%x", &w);
251 sscanf(appData.blackPieceColor+1, "%x", &b);
253 ch[i] = pixels[i+1][0];
255 if(strstr(pixels[i+1], "black")) colcode[i] = 0xFF000000 + (color ? b : 0);
256 if(strstr(pixels[i+1], "white")) colcode[i] = 0xFF000000 + w;
258 stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, p->size);
259 buf = (int *) malloc(p->size*stride);
260 for(i=0; i<p->size; i++) {
261 for(j=0; j<p->size; j++) {
262 char c = pixels[i+f+1][j];
264 for(k=0; ch[k] != c && k < f; k++);
265 buf[i*p->size + j] = colcode[k];
268 res = cairo_image_surface_create_for_data((unsigned char *) buf, CAIRO_FORMAT_ARGB32, p->size, p->size, stride);
269 if(cairo_surface_status(res) != CAIRO_STATUS_SUCCESS) { printf("bad pixmap convert\n"); exit(1); }
274 ScaleOnePiece (char *name, int color, int piece)
278 cairo_surface_t *img, *cs;
280 static cairo_surface_t *pngPieceImages[2][(int)BlackPawn+4]; // png 256 x 256 images
282 if(!*appData.pngDirectory) img = ConvertPixmap(color, piece); else
283 if(pngPieceImages[color][piece] == NULL) { // if PNG file for this piece was not yet read, read it now and store it
284 snprintf(buf, MSG_SIZ, "%s/%s%s.png", appData.pngDirectory, color ? "Black" : "White", pngPieceNames[piece]);
285 img = cairo_image_surface_create_from_png (buf);
286 if(cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) img = ConvertPixmap(color, piece);
288 pngPieceImages[color][piece] = img;
289 // create new bitmap to hold scaled piece image (and remove any old)
290 if(pngPieceBitmaps2[color][piece]) cairo_surface_destroy (pngPieceBitmaps2[color][piece]);
291 pngPieceBitmaps2[color][piece] = cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
292 if(piece <= WhiteKing) pngPieceBitmaps[color][piece] = cs;
293 // scaled copying of the raw png image
294 cr = cairo_create(cs);
295 w = cairo_image_surface_get_width (img);
296 h = cairo_image_surface_get_height (img);
297 cairo_scale(cr, squareSize/w, squareSize/h);
298 cairo_set_source_surface (cr, img, 0, 0);
308 for(p=0; pngPieceNames[p]; p++) {
309 ScaleOnePiece(pngPieceNames[p], 0, p);
310 ScaleOnePiece(pngPieceNames[p], 1, p);
316 { // [HGM] taken out of main
318 CreatePNGBoard(appData.liteBackTextureFile, 1);
319 CreatePNGBoard(appData.darkBackTextureFile, 0);
329 // [HGM] seekgraph: some low-level drawing routines (by JC, mostly)
332 Color (char *col, int n)
335 sscanf(col, "#%x", &c);
341 SetPen (cairo_t *cr, float w, char *col, int dash)
343 static const double dotted[] = {4.0, 4.0};
344 static int len = sizeof(dotted) / sizeof(dotted[0]);
345 cairo_set_line_width (cr, w);
346 cairo_set_source_rgba (cr, Color(col, 4), Color(col, 2), Color(col, 0), 1.0);
347 if(dash) cairo_set_dash (cr, dotted, len, 0.0);
350 void DrawSeekAxis( int x, int y, int xTo, int yTo )
355 cr = cairo_create (csBoardWindow);
357 cairo_move_to (cr, x, y);
358 cairo_line_to(cr, xTo, yTo );
360 SetPen(cr, 2, "#000000", 0);
367 void DrawSeekBackground( int left, int top, int right, int bottom )
369 cairo_t *cr = cairo_create (csBoardWindow);
371 cairo_rectangle (cr, left, top, right-left, bottom-top);
373 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4,1.0);
380 void DrawSeekText(char *buf, int x, int y)
382 cairo_t *cr = cairo_create (csBoardWindow);
384 cairo_select_font_face (cr, "Sans",
385 CAIRO_FONT_SLANT_NORMAL,
386 CAIRO_FONT_WEIGHT_NORMAL);
388 cairo_set_font_size (cr, 12.0);
390 cairo_move_to (cr, x, y+4);
391 cairo_set_source_rgba(cr, 0, 0, 0,1.0);
392 cairo_show_text( cr, buf);
398 void DrawSeekDot(int x, int y, int colorNr)
400 cairo_t *cr = cairo_create (csBoardWindow);
401 int square = colorNr & 0x80;
405 cairo_rectangle (cr, x-squareSize/9, y-squareSize/9, 2*(squareSize/9), 2*(squareSize/9));
407 cairo_arc(cr, x, y, squareSize/9, 0.0, 2*M_PI);
409 SetPen(cr, 2, "#000000", 0);
410 cairo_stroke_preserve(cr);
412 case 0: cairo_set_source_rgba(cr, 1.0, 0, 0,1.0); break;
413 case 1: cairo_set_source_rgba (cr, 0.0, 0.7, 0.2, 1.0); break;
414 default: cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); break;
425 int boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
426 int boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
428 csBoardWindow = GetOutputSurface(&mainOptions[W_BOARD], 0, 0);
429 csBoardBackup = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, boardWidth, boardHeight);
443 if (lineGap == 0) return;
445 /* [HR] Split this into 2 loops for non-square boards. */
447 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
448 gridSegments[i].x1 = 0;
450 lineGap + BOARD_WIDTH * (squareSize + lineGap);
451 gridSegments[i].y1 = gridSegments[i].y2
452 = lineGap / 2 + (i * (squareSize + lineGap));
455 for (j = 0; j < BOARD_WIDTH + 1; j++) {
456 gridSegments[j + i].y1 = 0;
457 gridSegments[j + i].y2 =
458 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
459 gridSegments[j + i].x1 = gridSegments[j + i].x2
460 = lineGap / 2 + (j * (squareSize + lineGap));
465 DoDrawGrid(cairo_surface_t *cs)
467 /* draws a grid starting around Nx, Ny squares starting at x,y */
473 cr = cairo_create (cs);
475 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
476 SetPen(cr, lineGap, "#000000", 0);
479 for (i = 0; i < BOARD_WIDTH + BOARD_HEIGHT + 2; i++)
481 cairo_move_to (cr, gridSegments[i].x1, gridSegments[i].y1);
482 cairo_line_to (cr, gridSegments[i].x2, gridSegments[i].y2);
495 DoDrawGrid(csBoardWindow);
496 if(!dual) DoDrawGrid(csBoardBackup);
500 DoDrawBorder (cairo_surface_t *cs, int x, int y, int type)
507 case 0: col = "#000000"; break;
508 case 1: col = appData.highlightSquareColor; break;
509 case 2: col = appData.premoveHighlightColor; break;
511 cr = cairo_create(cs);
512 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
513 cairo_rectangle(cr, x, y, squareSize+lineGap, squareSize+lineGap);
514 SetPen(cr, lineGap, col, 0);
519 DrawBorder (int x, int y, int type)
521 DoDrawBorder(csBoardWindow, x, y, type);
522 if(!dual) DoDrawBorder(csBoardBackup, x, y, type);
526 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
528 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
529 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
531 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
532 if(textureW[kind] < W*squareSize)
533 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
535 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
536 if(textureH[kind] < H*squareSize)
537 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
539 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
544 DrawLogo (void *handle, void *logo)
546 cairo_surface_t *img, *cs;
550 if(!logo || !handle) return;
551 cs = GetOutputSurface(handle, appData.logoSize, appData.logoSize/2);
552 img = cairo_image_surface_create_from_png (logo);
553 w = cairo_image_surface_get_width (img);
554 h = cairo_image_surface_get_height (img);
555 cr = cairo_create(cs);
556 cairo_scale(cr, (float)appData.logoSize/w, appData.logoSize/(2.*h));
557 cairo_set_source_surface (cr, img, 0, 0);
560 cairo_surface_destroy (img);
561 cairo_surface_destroy (cs);
565 BlankSquare (cairo_surface_t *dest, int x, int y, int color, ChessSquare piece, int fac)
566 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
570 cr = cairo_create (dest);
572 if ((useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
573 cairo_set_source_surface (cr, pngBoardBitmap[color], x*fac - x0, y*fac - y0);
574 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
575 cairo_rectangle (cr, x*fac, y*fac, squareSize, squareSize);
578 } else { // evenly colored squares
581 case 0: col = appData.darkSquareColor; break;
582 case 1: col = appData.lightSquareColor; break;
583 case 2: col = "#000000"; break;
585 SetPen(cr, 2.0, col, 0);
586 cairo_rectangle (cr, x, y, squareSize, squareSize);
593 pngDrawPiece (cairo_surface_t *dest, ChessSquare piece, int square_color, int x, int y)
598 if ((int)piece < (int) BlackPawn) {
604 if(appData.upsideDown && flipView) { p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
605 BlankSquare(dest, x, y, square_color, piece, 1); // erase previous contents with background
606 cr = cairo_create (dest);
607 cairo_set_source_surface (cr, pngPieceBitmaps[kind][piece], x, y);
613 DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
617 cr = cairo_create(cs);
618 cairo_arc(cr, x+r/2, y+r/2, r/2, 0.0, 2*M_PI);
619 if(appData.monoMode) {
620 SetPen(cr, 2, marker == 2 ? "#000000" : "#FFFFFF", 0);
621 cairo_stroke_preserve(cr);
622 SetPen(cr, 2, marker == 2 ? "#FFFFFF" : "#000000", 0);
624 SetPen(cr, 2, marker == 2 ? "#FF0000" : "#FFFF00", 0);
632 DrawDot (int marker, int x, int y, int r)
633 { // used for atomic captures; no need to draw on backup
635 DoDrawDot(csBoardWindow, marker, x, y, r);
639 DoDrawOneSquare (cairo_surface_t *dest, int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
640 { // basic front-end board-draw function: takes care of everything that can be in square:
641 // piece, background, coordinate/count, marker dot
644 if (piece == EmptySquare) {
645 BlankSquare(dest, x, y, square_color, piece, 1);
647 pngDrawPiece(dest, piece, square_color, x, y);
650 if(align) { // square carries inscription (coord or piece count)
652 cairo_text_extents_t te;
654 cr = cairo_create (dest);
655 cairo_select_font_face (cr, "Sans",
656 CAIRO_FONT_SLANT_NORMAL,
657 CAIRO_FONT_WEIGHT_BOLD);
659 cairo_set_font_size (cr, squareSize/4);
660 // calculate where it goes
661 cairo_text_extents (cr, string, &te);
664 xx += squareSize - te.width - te.x_bearing - 1;
665 yy += squareSize - te.height - te.y_bearing - 1;
666 } else if (align == 2) {
667 xx += te.x_bearing + 1, yy += -te.y_bearing + 1;
668 } else if (align == 3) {
669 xx += squareSize - te.width -te.x_bearing - 1;
670 yy += -te.y_bearing + 3;
671 } else if (align == 4) {
672 xx += te.x_bearing + 1, yy += -te.y_bearing + 3;
675 cairo_move_to (cr, xx-1, yy);
676 if(align < 3) cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
677 else cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
678 cairo_show_text (cr, string);
682 if(marker) { // print fat marker dot, if requested
683 DoDrawDot(dest, marker, x + squareSize/4, y+squareSize/4, squareSize/2);
688 DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
691 DoDrawOneSquare (csBoardWindow, x, y, piece, square_color, marker, string, align);
693 DoDrawOneSquare (csBoardBackup, x, y, piece, square_color, marker, string, align);
696 /**** Animation code by Hugh Fisher, DCS, ANU. ****/
698 /* Masks for XPM pieces. Black and white pieces can have
699 different shapes, but in the interest of retaining my
700 sanity pieces must have the same outline on both light
701 and dark squares, and all pieces must use the same
702 background square colors/images. */
704 static cairo_surface_t *c_animBufs[3*NrOfAnims]; // newBuf, saveBuf
707 InitAnimState (AnimNr anr)
709 DrawSeekOpen(); // set cs to board widget
710 if(c_animBufs[anr]) cairo_surface_destroy (c_animBufs[anr]);
711 if(c_animBufs[anr+2]) cairo_surface_destroy (c_animBufs[anr+2]);
712 c_animBufs[anr+4] = csBoardWindow;
713 c_animBufs[anr+2] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
714 c_animBufs[anr] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
721 InitAnimState(Player);
725 CairoOverlayPiece (ChessSquare piece, cairo_surface_t *dest)
727 static cairo_t *pieceSource;
728 pieceSource = cairo_create (dest);
729 cairo_set_source_surface (pieceSource, pngPieceBitmaps[!White(piece)][piece % BlackPawn], 0, 0);
730 if(doubleClick) cairo_paint_with_alpha (pieceSource, 0.6);
731 else cairo_paint(pieceSource);
732 cairo_destroy (pieceSource);
736 InsertPiece (AnimNr anr, ChessSquare piece)
738 CairoOverlayPiece(piece, c_animBufs[anr]);
742 DrawBlank (AnimNr anr, int x, int y, int startColor)
744 BlankSquare(c_animBufs[anr+2], x, y, startColor, EmptySquare, 0);
747 void CopyRectangle (AnimNr anr, int srcBuf, int destBuf,
748 int srcX, int srcY, int width, int height, int destX, int destY)
750 cairo_t *cr;// = cairo_create (c_animBufs[anr+destBuf]);
751 cr = cairo_create (c_animBufs[anr+destBuf]);
752 if(c_animBufs[anr+srcBuf] == csBoardWindow)
753 cairo_set_source_surface (cr, csBoardBackup, destX - srcX, destY - srcY);
755 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
756 cairo_rectangle (cr, destX, destY, width, height);
759 if(c_animBufs[anr+destBuf] == csBoardWindow) {
760 cr = cairo_create (csBoardBackup); // also draw to backup
761 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
762 cairo_rectangle (cr, destX, destY, width, height);
769 SetDragPiece (AnimNr anr, ChessSquare piece)
773 /* [AS] Arrow highlighting support */
776 DoDrawPolygon (cairo_surface_t *cs, Pnt arrow[], int nr)
780 cr = cairo_create (cs);
781 cairo_move_to (cr, arrow[nr-1].x, arrow[nr-1].y);
783 cairo_line_to(cr, arrow[i].x, arrow[i].y);
785 if(appData.monoMode) { // should we always outline arrow?
786 cairo_line_to(cr, arrow[0].x, arrow[0].y);
787 SetPen(cr, 2, "#000000", 0);
788 cairo_stroke_preserve(cr);
790 SetPen(cr, 2, appData.highlightSquareColor, 0);
798 DrawPolygon (Pnt arrow[], int nr)
800 DoDrawPolygon(csBoardWindow, arrow, nr);
801 if(!dual) DoDrawPolygon(csBoardBackup, arrow, nr);