4 ** all that is necessary for drawing a gipf-board and the pieces on it
7 ** Copyright (C) 1998 Kurt Van den Branden
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 2 of the License, or
12 ** (at your option) any later version.
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <FL/fl_draw.H>
29 #define round(x) (int)(x + 0.5)
31 void shmpos (void * data
);
34 ** all measurements are based on a square of 2 * 2.5
36 // x and y-position of each first point of a column
37 const double rowbase
[9][2] = {
39 {.3505, 2.125}, // row b
40 {.567, 2.25}, // row c
41 {.7835, 2.375}, // row d
43 {1.2165, 2.375}, // row f
44 {1.433, 2.25}, // row g
45 {1.6495, 2.125}, // row h
49 /* lines on the board */
50 const position linetable
[21][2] = {
51 {{0, 4}, {5, 8}}, {{0, 3}, {6, 7}}, {{0, 2}, {7, 6}},
52 {{0, 1}, {8, 5}}, {{1, 1}, {8, 4}}, {{2, 1}, {8, 3}},
53 {{3, 1}, {8, 2}}, {{0, 2}, {5, 1}}, {{0, 3}, {6, 1}},
54 {{0, 4}, {7, 1}}, {{0, 5}, {8, 1}}, {{1, 6}, {8, 2}},
55 {{2, 7}, {8, 3}}, {{3, 8}, {8, 4}}, {{1, 6}, {1, 1}},
56 {{2, 7}, {2, 1}}, {{3, 8}, {3, 1}}, {{4, 9}, {4, 1}},
57 {{5, 8}, {5, 1}}, {{6, 7}, {6, 1}}, {{7, 6}, {7, 1}}
60 /* possible from-points */
61 const position fromtable
[24] = {
62 {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 6},
63 {2, 7}, {3, 8}, {4, 9}, {5, 8}, {6, 7}, {7, 6},
64 {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {7, 1},
65 {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1},
68 /* possible to-points */
69 const position totable
[18] = {
70 {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 6}, {3, 7},
71 {4, 8}, {5, 7}, {6, 6}, {7, 5}, {7, 4}, {7, 3},
72 {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}
76 const position hexagon
[7] = {
77 {1, 2}, {1, 5}, {4, 8}, {7, 5}, {7, 2}, {4, 2}, {1, 2}
83 fl_board::fl_board(int X
,int Y
,int W
,int H
,const char *l
)
84 : Fl_Widget (X
, Y
, W
, H
, l
)
109 // I don't know if this is a good solution
110 // lyellow = FL_COLOR_CUBE +
111 // FL_RED_MULTIPLY * 4 +
112 // FL_GREEN_MULTIPLY * 7 +
113 // FL_BLUE_MULTIPLY * 3;
114 lyellow
= fl_color_cube(255 * FL_NUM_RED
/256,
115 255 * FL_NUM_GREEN
/256,
116 200 * FL_NUM_BLUE
/256);
124 fl_board::~fl_board ()
130 emptyll (row
, del_position_f
);
144 ** the fl_board class should only handle one event on its own
145 ** when an FL_PUSH occurs, the widget must check in what state it is
146 ** and where a push can have effect in this state
148 int fl_board::handle (int event
)
150 ::position
* temppos
;
155 /* check what was pushed */
156 if (theboard
== NULL
)
159 if (state
== BOARD_PLAY
)
161 if (checkfrompush ())
168 else if (state
== BOARD_EDIT
)
173 // state = BOARD_NONE
178 if (positionhints
== 0)
181 temppos
= getmousepos ();
183 // mouse was moved to an unrecognized position
186 // stop timer, even if it is not running
187 Fl::remove_timeout (shmpos
, (void *) this);
191 del_position (showpos
);
202 // mouse was moved to a known position
203 // previous position was NULL
207 Fl::add_timeout (.5, shmpos
, (void *) this);
213 // check if mouse was moved to a different position
214 if ((showpos
->row
== temppos
->row
) &&
215 (showpos
->col
== temppos
->col
))
217 del_position (temppos
);
221 // new known position
223 // stop timer, even if it is not running
224 Fl::remove_timeout (shmpos
, (void *) this);
226 del_position (showpos
);
236 Fl::add_timeout (.5, shmpos
, (void *) this);
242 if (positionhints
== 0)
245 Fl::remove_timeout (shmpos
, (void *) this);
249 del_position (showpos
);
268 ** check if one of the from-points was pushed
270 int fl_board::checkfrompush ()
278 pushx
= Fl::event_x ();
279 pushy
= Fl::event_y ();
282 for (i
= 0; i
< 24; i
++)
284 pos2coor (&(fromtable
[i
]), x
, y
);
286 if ((pushx
> (x
- box
)) &&
287 (pushy
> (y
- box
)) &&
288 (pushx
< (x
+ box
)) &&
291 if ((from
== NULL
) ||
292 (from
->col
!= fromtable
[i
].col
) ||
293 (from
->row
!= fromtable
[i
].row
))
295 setfrom (& fromtable
[i
]);
298 else if (gipfpossible
== 1)
300 fromtype
= (fromtype
== 1 ? 0 : 1);
312 ** check if one of the to-points was pushed
314 int fl_board::checktopush ()
322 pushx
= Fl::event_x ();
323 pushy
= Fl::event_y ();
326 for (i
= 0; i
< 18; i
++)
328 pos2coor (&(totable
[i
]), x
, y
);
330 if ((pushx
> (x
- box
)) &&
331 (pushy
> (y
- box
)) &&
332 (pushx
< (x
+ box
)) &&
335 setto (& totable
[i
]);
346 ** check if any point on the board was pushed
348 int fl_board::checkeditpush ()
355 ::position
* temppos
;
358 pushx
= Fl::event_x ();
359 pushy
= Fl::event_y ();
362 temppos
= new_position ();
363 /* check all board positions */
364 for (i
= 1; i
< 8; i
++)
367 for (j
= 2; j
<= b_colsize (i
); j
++)
371 pos2coor (temppos
, x
, y
);
372 if ((pushx
> (x
- box
)) &&
373 (pushy
> (y
- box
)) &&
374 (pushx
< (x
+ box
)) &&
377 if (b_ppiece (theboard
, temppos
) != '.')
379 if ((nboard
= b_edit_piece (theboard
, temppos
, '.'))
388 if ((nboard
= b_edit_piece (theboard
, temppos
, editpiece
))
396 changecountervalues ();
408 position
* fl_board::getmousepos ()
415 ::position
* temppos
;
416 int colsize
[] = {5, 6, 7, 8, 9, 8, 7, 6, 5};
418 pushx
= Fl::event_x ();
419 pushy
= Fl::event_y ();
422 temppos
= new_position ();
424 for (i
= 0; i
< 9; i
++)
427 for (j
= 1; j
<= colsize
[i
]; j
++)
431 pos2coor (temppos
, x
, y
);
432 if ((pushx
> (x
- box
)) &&
433 (pushy
> (y
- box
)) &&
434 (pushx
< (x
+ box
)) &&
447 void fl_board::draw ()
457 ::position
* temppos
;
461 if (!(dam
& FL_DAMAGE_ALL
) &&
462 (dam
& FL_DAMAGE_ANIM
))
463 { /* draw for move-animation */
464 /* maybe things can be speeded up by using clipping */
465 /* calculate clipping-region */
475 fl_clip (clip_x
, clip_y
, clip_w
, clip_h
);
477 /* set everything to background color */
478 // fl_color (Fl_Widget::color());
480 fl_rectf (clip_x
, clip_y
, clip_w
, clip_h
);
484 fl_color (FL_WHITE
); // white
488 for (i
= 0; i
< 7; i
++)
490 pos2coor (&(hexagon
[i
]), x1
, y1
);
492 /* didn't look nice on mswin */
493 if ((i
> 0) && (i
< 4))
502 fl_color (FL_BLACK
); // black
505 for (i
= 0; i
< 21; i
++)
507 pos2coor (&(linetable
[i
][0]), x1
, y1
);
508 pos2coor (&(linetable
[i
][1]), x2
, y2
);
510 /* I have to add 1 to the third parameter, or
511 ** vertical lines don't get drawn on ms windows */
512 if (fl_not_clipped (min (x1
, x2
), min (y1
, y2
),
513 max (x1
, x2
) - min (x1
, x2
) + 1,
514 max (y1
, y2
) - min (y1
, y2
)))
515 fl_line (x1
, y1
, x2
, y2
);
521 for (i
= 0; i
< 24; i
++)
523 pos2coor (&(fromtable
[i
]), x1
, y1
);
524 if (fl_not_clipped (x1
- straal
, y1
- straal
,
525 x1
+ straal
, y1
+ straal
))
528 fl_circle (x1
, y1
, straal
);
532 fl_pie (x1
- straal
, y1
- straal
, diam
, diam
, 0, 360);
537 fl_font (FL_HELVETICA
, base
/12);
539 height
= fl_height () / 2 - fl_descent ();
540 for (i
= 0; i
< 9; i
++)
542 sprintf (tempstr
, "%c1", i
+'a');
543 width
= round (fl_width (tempstr
) / 2);
544 x1
= xoffset
+ round (rowbase
[i
][0] * base
);
545 y1
= yoffset
+ round ((rowbase
[i
][1] - .5 * .25) * base
);
546 fl_draw (tempstr
, x1
- width
, y1
+ height
);
548 nr
= (i
< 5 ? i
+ 5 : 13 - i
);
549 sprintf (tempstr
, "%c%d", i
+'a', nr
);
550 width
= round (fl_width (tempstr
) / 2);
551 y1
= yoffset
+ round ((rowbase
[i
][1] - (nr
+ .5) * .25) * base
);
552 fl_draw (tempstr
, x1
- width
, y1
+ height
);
555 /* draw pieces if there is a board */
556 if (theboard
!= NULL
)
558 temppos
= new_position ();
560 for (i
= 1; i
< 8; i
++)
563 for (j
= 2; j
<= b_colsize (i
); j
++)
566 if (b_ppiece (theboard
, temppos
) != '.')
568 drawpiece (temppos
, b_ppiece (theboard
, temppos
));
574 /* draw from and to (if necessary) */
575 if (state
== BOARD_PLAY
)
579 piece
= b_next_piece (theboard
);
582 piece
= b_otherpiece (piece
);
584 drawpiece (from
, piece
);
589 drawcross (to
->col
, to
->row
);
593 /* draw crosses on row of pieces, if necessary */
598 while ((posp
= (::position
*) llitembynr (row
, counter
)) != NULL
)
600 drawcross (posp
->col
, posp
->row
);
605 if (animlist
!= NULL
)
612 if ((positionhints
!= 0) && (showpos
!= NULL
) && (showflag
== 1))
614 posstr
= postostr (showpos
);
616 pos2coor (showpos
, x1
, y1
);
617 width
= 8 + (int) fl_width (posstr
);
618 height
= 4 + fl_height ();
622 if (fl_not_clipped (x1
, y1
, width
+ 2, height
+ 2))
624 fl_color (FL_DARK2
); // 125,125,125
625 fl_rectf (x1
+ 2, y1
+ 2, width
, height
);
626 fl_color (lyellow
); // 255,255,200
627 fl_rectf (x1
, y1
, width
, height
);
629 fl_rect (x1
, y1
, width
, height
);
630 fl_draw (posstr
, x1
+ 4, y1
+ height
- fl_descent () - 2);
642 void fl_board::drawpiece (::position
* pos
, char piece
)
652 /* don't draw piece if in animation-list */
654 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
658 if ((posp_col (pos
) == posp_col (mpiece
->from
)) &&
659 (posp_row (pos
) == posp_row (mpiece
->from
)))
663 /* calculate position of center of the piece */
664 pos2coor (pos
, x
, y
);
666 drawpiece (x
, y
, piece
);
671 void fl_board::drawpiece (int x
, int y
, char piece
)
677 /* calculate size of piece */
683 if (straal3
> (straal2
- 2))
684 straal3
= straal2
- 2;
686 if (!fl_not_clipped (x
- straal
, y
- straal
, diam
, diam
))
689 if ((piece
== 'o') ||
700 fl_circle (x
, y
, straal
);
705 fl_circle (x
, y
, straal
);
708 if ((piece
== 'O') ||
712 // fl_begin_complex_polygon ();
713 // fl_arc (x, y, straal2, 0, 360);
715 // fl_arc (x, y, straal3, 0, 360);
716 // fl_end_complex_polygon ();
718 fl_circle (x
, y
, straal2
);
726 fl_circle (x
, y
, straal3
);
732 fl_pie (x
- straal
+ 1, y
- straal
+ 1, diam
- 2, diam
- 2, 0, 360);
734 fl_pie (x
- straal
, y
- straal
, diam
- 1, diam
- 1, 0, 360);
738 fl_arc (x
- straal
, y
- straal
, diam
, diam
, 0, 360);
740 if ((piece
== 'O') ||
744 fl_arc (x
- straal2
, y
- straal2
, diam2
, diam2
, 0, 360);
745 fl_arc (x
- straal2
+ 1, y
- straal2
+ 1, diam2
-2, diam2
-2, 0, 360);
753 void fl_board::drawanimpieces (void)
761 int x
, y
, x1
, y1
, x2
, y2
;
764 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
769 /* calculate position of center of the piece */
770 pos2coor (mpiece
->from
, x1
, y1
);
771 pos2coor (mpiece
->to
, x2
, y2
);
772 x
= x1
+ (x2
- x1
) * step
/ maxstep
;
773 y
= y1
+ (y2
- y1
) * step
/ maxstep
;
775 drawpiece (x
, y
, mpiece
->piece
);
780 while ((mpiece
= (struct movepiece
*) llrembynr (animlist
, 1)) != NULL
)
794 void fl_board::drawcross (int col
, int row
)
800 /* calculate position of center of the piece */
803 pos2coor (&temppos
, x
, y
);
807 if (!fl_not_clipped (x
- straal
, y
- straal
, straal
* 2, straal
* 2))
813 ** I draw a lot of lines here to get the impression of a
816 fl_line (x
- straal
, y
- straal
, x
+ straal
, y
+ straal
);
817 fl_line (x
- straal
+ 1, y
- straal
, x
+ straal
, y
+ straal
- 1);
818 fl_line (x
- straal
, y
- straal
+ 1, x
+ straal
- 1, y
+ straal
);
820 fl_line (x
+ straal
, y
- straal
, x
- straal
, y
+ straal
);
821 fl_line (x
+ straal
- 1, y
- straal
, x
- straal
, y
+ straal
- 1);
822 fl_line (x
+ straal
, y
- straal
+ 1, x
- straal
+ 1, y
+ straal
);
828 void fl_board::resize (int x
, int y
, int w
, int h
)
830 Fl_Widget::resize (x
, y
, w
, h
);
836 del_position (showpos
);
851 ** to be used at every resize-event and at class-creation
853 void fl_board::calcsizes ()
858 width
= round (w() / 2.0);
859 height
= round (h() / 2.5);
860 base
= min (width
, height
);
862 xoffset
= round((w() - base
* 2.0) / 2) + x();
863 yoffset
= round((h() - base
* 2.5) / 2) + y();
870 ** calculate screen-coordinates starting from a board-position
872 // solution: Fl_Input_ has a 'position' member function
873 inline void fl_board::pos2coor (const ::position
*pos
, int& x
, int& y
)
875 x
= xoffset
+ round (rowbase
[pos
->col
][0] * base
);
876 y
= yoffset
+ round ((rowbase
[pos
->col
][1] - pos
->row
* .25) * base
);
882 void fl_board::setoutputwidgets (Fl_Output
* wp
, Fl_Output
* wl
,
883 fl_pile
* wpi
, Fl_Output
* bp
,
884 Fl_Output
* bl
, fl_pile
* bpi
,
885 Fl_Output
* from_o
, Fl_Output
* to_o
)
890 wpile
->setcolor ('o');
895 bpile
->setcolor ('x');
900 changecountervalues ();
901 changefromtovalues ();
906 void fl_board::changefromtovalues ()
912 tempstr
= postostr (from
);
913 t_from
->value (tempstr
);
918 t_from
->value (NULL
);
923 tempstr
= postostr (to
);
924 t_to
->value (tempstr
);
938 void fl_board::changecountervalues ()
944 if (theboard
!= NULL
)
946 sprintf (tempstr
, "%d", b_white (theboard
));
947 wpieces
->value (tempstr
);
948 sprintf (tempstr
, "lost: %d", b_white_lost (theboard
));
949 wlost
->value (tempstr
);
950 wpile
->setvalue (b_white (theboard
));
952 sprintf (tempstr
, "%d", b_black (theboard
));
953 bpieces
->value (tempstr
);
954 sprintf (tempstr
, "lost: %d", b_black_lost (theboard
));
955 blost
->value (tempstr
);
956 bpile
->setvalue (b_black (theboard
));
960 wpieces
->value (NULL
);
962 wpile
->setvalue (-1);
963 bpieces
->value (NULL
);
965 bpile
->setvalue (-1);
973 void fl_board::setboard (board
* newboard
)
975 if (b_compare (newboard
, theboard
) == 0)
976 { /* the new is the same as the old */
980 if (theboard
!= NULL
)
984 theboard
= b_copy (newboard
);
986 changecountervalues ();
993 void fl_board::setfrom (const ::position
* newfrom
)
999 from
= (::position
*) copy_position ((void *) newfrom
);
1001 changefromtovalues ();
1007 void fl_board::setto (const ::position
* newto
)
1009 if ((newto
!= NULL
) && (from
!= NULL
) && (to
!= NULL
) &&
1010 (execbutton
!= NULL
) &&
1011 (posp_col (to
) == posp_col (newto
)) &&
1012 (posp_row (to
) == posp_row (newto
)))
1014 execbutton
->do_callback ();
1021 to
= (::position
*) copy_position ((void *) newto
);
1023 changefromtovalues ();
1029 void fl_board::seteditpiece (char newpiece
)
1031 editpiece
= newpiece
;
1035 int fl_board::setlostwhite (int val
)
1039 if (theboard
== NULL
)
1042 if ((nboard
= b_edit_lostwhite (theboard
, val
)) != NULL
)
1047 changecountervalues ();
1049 return (b_white_lost (theboard
));
1053 int fl_board::setlostblack (int val
)
1057 if (theboard
== NULL
)
1060 if ((nboard
= b_edit_lostblack (theboard
, val
)) != NULL
)
1065 changecountervalues ();
1067 return (b_black_lost (theboard
));
1071 void fl_board::setstate (int newstate
)
1075 if (state
!= BOARD_PLAY
)
1083 void fl_board::showmousepos ()
1085 if (showpos
!= NULL
)
1095 void shmpos (void * data
)
1097 fl_board
* boardobject
= (fl_board
*) data
;
1099 boardobject
->showmousepos ();
1105 void fl_board::setgipfpossible (int flag
)
1120 void fl_board::setrow (listheader
* rowp
)
1124 emptyll (row
, del_position_f
);
1128 row
= copy_position_row (rowp
);
1137 void fl_board::initanim (int st
, listheader
* al
)
1144 } * mpiece
, * npiece
;
1149 newl
= (listheader
*) malloc (sizeof (listheader
));
1153 while ((mpiece
= (struct movepiece
*) llitembynr (al
, counter
))
1158 npiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1159 npiece
->piece
= mpiece
->piece
;
1160 npiece
->from
= (::position
*) copy_position ((void *) mpiece
->from
);
1161 npiece
->to
= (::position
*) copy_position ((void *) mpiece
->to
);
1163 pushll (newl
, npiece
);
1166 if (animlist
!= NULL
)
1168 while ((mpiece
= (struct movepiece
*) llrembynr (animlist
, 1)) != NULL
)
1170 free (mpiece
->from
);
1183 void fl_board::calc_clipping ()
1195 mpiece
= (struct movepiece
*) llitembynr (animlist
, 1);
1196 pos2coor (mpiece
->from
, x1
, y1
);
1198 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
1202 pos2coor (mpiece
->to
, x2
, y2
);
1206 /* the -2 and +2 are used for a little security */
1207 clip_x
= min (x1
, x2
) - straal
- 2;
1208 clip_y
= min (y1
, y2
) - straal
- 2;
1209 clip_w
= max (x1
, x2
) - clip_x
+ straal
+ 2;
1210 clip_h
= max (y1
, y2
) - clip_y
+ straal
+ 2;