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);
252 res = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->size, p->size);
253 stride = cairo_image_surface_get_stride(res);
254 buf = (int *) cairo_image_surface_get_data(res);
256 ch[i] = pixels[i+1][0];
258 if(strstr(pixels[i+1], "black")) colcode[i] = 0xFF000000 + (color ? b : 0);
259 if(strstr(pixels[i+1], "white")) colcode[i] = 0xFF000000 + w;
261 for(i=0; i<p->size; i++) {
262 for(j=0; j<p->size; j++) {
263 char c = pixels[i+f+1][j];
265 for(k=0; ch[k] != c && k < f; k++);
266 buf[i*p->size + j] = colcode[k];
269 cairo_surface_mark_dirty(res);
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((img = pngPieceImages[color][piece]) == NULL) { // if PNG file for this piece was not yet read, read it now and store it
283 if(!*appData.pngDirectory) img = ConvertPixmap(color, piece); else {
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);
289 pngPieceImages[color][piece] = img;
290 // create new bitmap to hold scaled piece image (and remove any old)
291 if(pngPieceBitmaps2[color][piece]) cairo_surface_destroy (pngPieceBitmaps2[color][piece]);
292 pngPieceBitmaps2[color][piece] = cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
293 if(piece <= WhiteKing) pngPieceBitmaps[color][piece] = cs;
294 // scaled copying of the raw png image
295 cr = cairo_create(cs);
296 w = cairo_image_surface_get_width (img);
297 h = cairo_image_surface_get_height (img);
298 cairo_scale(cr, squareSize/w, squareSize/h);
299 cairo_set_source_surface (cr, img, 0, 0);
309 for(p=0; pngPieceNames[p]; p++) {
310 ScaleOnePiece(pngPieceNames[p], 0, p);
311 ScaleOnePiece(pngPieceNames[p], 1, p);
317 { // [HGM] taken out of main
319 CreatePNGBoard(appData.liteBackTextureFile, 1);
320 CreatePNGBoard(appData.darkBackTextureFile, 0);
330 // [HGM] seekgraph: some low-level drawing routines (by JC, mostly)
333 Color (char *col, int n)
336 sscanf(col, "#%x", &c);
342 SetPen (cairo_t *cr, float w, char *col, int dash)
344 static const double dotted[] = {4.0, 4.0};
345 static int len = sizeof(dotted) / sizeof(dotted[0]);
346 cairo_set_line_width (cr, w);
347 cairo_set_source_rgba (cr, Color(col, 4), Color(col, 2), Color(col, 0), 1.0);
348 if(dash) cairo_set_dash (cr, dotted, len, 0.0);
351 void DrawSeekAxis( int x, int y, int xTo, int yTo )
356 cr = cairo_create (csBoardWindow);
358 cairo_move_to (cr, x, y);
359 cairo_line_to(cr, xTo, yTo );
361 SetPen(cr, 2, "#000000", 0);
368 void DrawSeekBackground( int left, int top, int right, int bottom )
370 cairo_t *cr = cairo_create (csBoardWindow);
372 cairo_rectangle (cr, left, top, right-left, bottom-top);
374 cairo_set_source_rgba(cr, 0.8, 0.8, 0.4,1.0);
381 void DrawSeekText(char *buf, int x, int y)
383 cairo_t *cr = cairo_create (csBoardWindow);
385 cairo_select_font_face (cr, "Sans",
386 CAIRO_FONT_SLANT_NORMAL,
387 CAIRO_FONT_WEIGHT_NORMAL);
389 cairo_set_font_size (cr, 12.0);
391 cairo_move_to (cr, x, y+4);
392 cairo_set_source_rgba(cr, 0, 0, 0,1.0);
393 cairo_show_text( cr, buf);
399 void DrawSeekDot(int x, int y, int colorNr)
401 cairo_t *cr = cairo_create (csBoardWindow);
402 int square = colorNr & 0x80;
406 cairo_rectangle (cr, x-squareSize/9, y-squareSize/9, 2*(squareSize/9), 2*(squareSize/9));
408 cairo_arc(cr, x, y, squareSize/9, 0.0, 2*M_PI);
410 SetPen(cr, 2, "#000000", 0);
411 cairo_stroke_preserve(cr);
413 case 0: cairo_set_source_rgba(cr, 1.0, 0, 0,1.0); break;
414 case 1: cairo_set_source_rgba (cr, 0.0, 0.7, 0.2, 1.0); break;
415 default: cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); break;
426 int boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
427 int boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
429 csBoardWindow = GetOutputSurface(&mainOptions[W_BOARD], 0, 0);
430 csBoardBackup = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, boardWidth, boardHeight);
444 if (lineGap == 0) return;
446 /* [HR] Split this into 2 loops for non-square boards. */
448 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
449 gridSegments[i].x1 = 0;
451 lineGap + BOARD_WIDTH * (squareSize + lineGap);
452 gridSegments[i].y1 = gridSegments[i].y2
453 = lineGap / 2 + (i * (squareSize + lineGap));
456 for (j = 0; j < BOARD_WIDTH + 1; j++) {
457 gridSegments[j + i].y1 = 0;
458 gridSegments[j + i].y2 =
459 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
460 gridSegments[j + i].x1 = gridSegments[j + i].x2
461 = lineGap / 2 + (j * (squareSize + lineGap));
466 DoDrawGrid(cairo_surface_t *cs)
468 /* draws a grid starting around Nx, Ny squares starting at x,y */
474 cr = cairo_create (cs);
476 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
477 SetPen(cr, lineGap, "#000000", 0);
480 for (i = 0; i < BOARD_WIDTH + BOARD_HEIGHT + 2; i++)
482 cairo_move_to (cr, gridSegments[i].x1, gridSegments[i].y1);
483 cairo_line_to (cr, gridSegments[i].x2, gridSegments[i].y2);
496 DoDrawGrid(csBoardWindow);
497 if(!dual) DoDrawGrid(csBoardBackup);
501 DoDrawBorder (cairo_surface_t *cs, int x, int y, int type)
508 case 0: col = "#000000"; break;
509 case 1: col = appData.highlightSquareColor; break;
510 case 2: col = appData.premoveHighlightColor; break;
512 cr = cairo_create(cs);
513 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
514 cairo_rectangle(cr, x, y, squareSize+lineGap, squareSize+lineGap);
515 SetPen(cr, lineGap, col, 0);
520 DrawBorder (int x, int y, int type)
522 DoDrawBorder(csBoardWindow, x, y, type);
523 if(!dual) DoDrawBorder(csBoardBackup, x, y, type);
527 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
529 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
530 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
532 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
533 if(textureW[kind] < W*squareSize)
534 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
536 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
537 if(textureH[kind] < H*squareSize)
538 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
540 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
545 DrawLogo (void *handle, void *logo)
547 cairo_surface_t *img, *cs;
551 if(!logo || !handle) return;
552 cs = GetOutputSurface(handle, appData.logoSize, appData.logoSize/2);
553 img = cairo_image_surface_create_from_png (logo);
554 w = cairo_image_surface_get_width (img);
555 h = cairo_image_surface_get_height (img);
556 cr = cairo_create(cs);
557 cairo_scale(cr, (float)appData.logoSize/w, appData.logoSize/(2.*h));
558 cairo_set_source_surface (cr, img, 0, 0);
561 cairo_surface_destroy (img);
562 cairo_surface_destroy (cs);
566 BlankSquare (cairo_surface_t *dest, int x, int y, int color, ChessSquare piece, int fac)
567 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
571 cr = cairo_create (dest);
573 if ((useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
574 cairo_set_source_surface (cr, pngBoardBitmap[color], x*fac - x0, y*fac - y0);
575 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
576 cairo_rectangle (cr, x*fac, y*fac, squareSize, squareSize);
579 } else { // evenly colored squares
582 case 0: col = appData.darkSquareColor; break;
583 case 1: col = appData.lightSquareColor; break;
584 case 2: col = "#000000"; break;
586 SetPen(cr, 2.0, col, 0);
587 cairo_rectangle (cr, x, y, squareSize, squareSize);
594 pngDrawPiece (cairo_surface_t *dest, ChessSquare piece, int square_color, int x, int y)
599 if ((int)piece < (int) BlackPawn) {
605 if(appData.upsideDown && flipView) { p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
606 BlankSquare(dest, x, y, square_color, piece, 1); // erase previous contents with background
607 cr = cairo_create (dest);
608 cairo_set_source_surface (cr, pngPieceBitmaps[kind][piece], x, y);
614 DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
618 cr = cairo_create(cs);
619 cairo_arc(cr, x+r/2, y+r/2, r/2, 0.0, 2*M_PI);
620 if(appData.monoMode) {
621 SetPen(cr, 2, marker == 2 ? "#000000" : "#FFFFFF", 0);
622 cairo_stroke_preserve(cr);
623 SetPen(cr, 2, marker == 2 ? "#FFFFFF" : "#000000", 0);
625 SetPen(cr, 2, marker == 2 ? "#FF0000" : "#FFFF00", 0);
633 DrawDot (int marker, int x, int y, int r)
634 { // used for atomic captures; no need to draw on backup
636 DoDrawDot(csBoardWindow, marker, x, y, r);
640 DoDrawOneSquare (cairo_surface_t *dest, int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
641 { // basic front-end board-draw function: takes care of everything that can be in square:
642 // piece, background, coordinate/count, marker dot
645 if (piece == EmptySquare) {
646 BlankSquare(dest, x, y, square_color, piece, 1);
648 pngDrawPiece(dest, piece, square_color, x, y);
651 if(align) { // square carries inscription (coord or piece count)
653 cairo_text_extents_t te;
655 cr = cairo_create (dest);
656 cairo_select_font_face (cr, "Sans",
657 CAIRO_FONT_SLANT_NORMAL,
658 CAIRO_FONT_WEIGHT_BOLD);
660 cairo_set_font_size (cr, squareSize/4);
661 // calculate where it goes
662 cairo_text_extents (cr, string, &te);
665 xx += squareSize - te.width - te.x_bearing - 1;
666 yy += squareSize - te.height - te.y_bearing - 1;
667 } else if (align == 2) {
668 xx += te.x_bearing + 1, yy += -te.y_bearing + 1;
669 } else if (align == 3) {
670 xx += squareSize - te.width -te.x_bearing - 1;
671 yy += -te.y_bearing + 3;
672 } else if (align == 4) {
673 xx += te.x_bearing + 1, yy += -te.y_bearing + 3;
676 cairo_move_to (cr, xx-1, yy);
677 if(align < 3) cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
678 else cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
679 cairo_show_text (cr, string);
683 if(marker) { // print fat marker dot, if requested
684 DoDrawDot(dest, marker, x + squareSize/4, y+squareSize/4, squareSize/2);
689 DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, char *string, int align)
692 DoDrawOneSquare (csBoardWindow, x, y, piece, square_color, marker, string, align);
694 DoDrawOneSquare (csBoardBackup, x, y, piece, square_color, marker, string, align);
697 /**** Animation code by Hugh Fisher, DCS, ANU. ****/
699 /* Masks for XPM pieces. Black and white pieces can have
700 different shapes, but in the interest of retaining my
701 sanity pieces must have the same outline on both light
702 and dark squares, and all pieces must use the same
703 background square colors/images. */
705 static cairo_surface_t *c_animBufs[3*NrOfAnims]; // newBuf, saveBuf
708 InitAnimState (AnimNr anr)
710 DrawSeekOpen(); // set cs to board widget
711 if(c_animBufs[anr]) cairo_surface_destroy (c_animBufs[anr]);
712 if(c_animBufs[anr+2]) cairo_surface_destroy (c_animBufs[anr+2]);
713 c_animBufs[anr+4] = csBoardWindow;
714 c_animBufs[anr+2] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
715 c_animBufs[anr] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
722 InitAnimState(Player);
726 CairoOverlayPiece (ChessSquare piece, cairo_surface_t *dest)
728 static cairo_t *pieceSource;
729 pieceSource = cairo_create (dest);
730 cairo_set_source_surface (pieceSource, pngPieceBitmaps[!White(piece)][piece % BlackPawn], 0, 0);
731 if(doubleClick) cairo_paint_with_alpha (pieceSource, 0.6);
732 else cairo_paint(pieceSource);
733 cairo_destroy (pieceSource);
737 InsertPiece (AnimNr anr, ChessSquare piece)
739 CairoOverlayPiece(piece, c_animBufs[anr]);
743 DrawBlank (AnimNr anr, int x, int y, int startColor)
745 BlankSquare(c_animBufs[anr+2], x, y, startColor, EmptySquare, 0);
748 void CopyRectangle (AnimNr anr, int srcBuf, int destBuf,
749 int srcX, int srcY, int width, int height, int destX, int destY)
751 cairo_t *cr;// = cairo_create (c_animBufs[anr+destBuf]);
752 cr = cairo_create (c_animBufs[anr+destBuf]);
753 if(c_animBufs[anr+srcBuf] == csBoardWindow)
754 cairo_set_source_surface (cr, csBoardBackup, destX - srcX, destY - srcY);
756 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
757 cairo_rectangle (cr, destX, destY, width, height);
760 if(c_animBufs[anr+destBuf] == csBoardWindow) {
761 cr = cairo_create (csBoardBackup); // also draw to backup
762 cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
763 cairo_rectangle (cr, destX, destY, width, height);
770 SetDragPiece (AnimNr anr, ChessSquare piece)
774 /* [AS] Arrow highlighting support */
777 DoDrawPolygon (cairo_surface_t *cs, Pnt arrow[], int nr)
781 cr = cairo_create (cs);
782 cairo_move_to (cr, arrow[nr-1].x, arrow[nr-1].y);
784 cairo_line_to(cr, arrow[i].x, arrow[i].y);
786 if(appData.monoMode) { // should we always outline arrow?
787 cairo_line_to(cr, arrow[0].x, arrow[0].y);
788 SetPen(cr, 2, "#000000", 0);
789 cairo_stroke_preserve(cr);
791 SetPen(cr, 2, appData.highlightSquareColor, 0);
799 DrawPolygon (Pnt arrow[], int nr)
801 DoDrawPolygon(csBoardWindow, arrow, nr);
802 if(!dual) DoDrawPolygon(csBoardBackup, arrow, nr);