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>
30 #define min(x,y) (x < y ? x : y)
34 #define max(x,y) (x > y ? x : y)
37 #define round(x) (int)(x + 0.5)
39 void shmpos (void * data
);
42 ** all measurements are based on a square of 2 * 2.5
44 // x and y-position of each first point of a column
45 const double rowbase
[9][2] = {
47 {.3505, 2.125}, // row b
48 {.567, 2.25}, // row c
49 {.7835, 2.375}, // row d
51 {1.2165, 2.375}, // row f
52 {1.433, 2.25}, // row g
53 {1.6495, 2.125}, // row h
57 /* lines on the board */
58 const position linetable
[21][2] = {
59 {{0, 4}, {5, 8}}, {{0, 3}, {6, 7}}, {{0, 2}, {7, 6}},
60 {{0, 1}, {8, 5}}, {{1, 1}, {8, 4}}, {{2, 1}, {8, 3}},
61 {{3, 1}, {8, 2}}, {{0, 2}, {5, 1}}, {{0, 3}, {6, 1}},
62 {{0, 4}, {7, 1}}, {{0, 5}, {8, 1}}, {{1, 6}, {8, 2}},
63 {{2, 7}, {8, 3}}, {{3, 8}, {8, 4}}, {{1, 6}, {1, 1}},
64 {{2, 7}, {2, 1}}, {{3, 8}, {3, 1}}, {{4, 9}, {4, 1}},
65 {{5, 8}, {5, 1}}, {{6, 7}, {6, 1}}, {{7, 6}, {7, 1}}
68 /* possible from-points */
69 const position fromtable
[24] = {
70 {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {1, 6},
71 {2, 7}, {3, 8}, {4, 9}, {5, 8}, {6, 7}, {7, 6},
72 {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {7, 1},
73 {6, 1}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1},
76 /* possible to-points */
77 const position totable
[18] = {
78 {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 6}, {3, 7},
79 {4, 8}, {5, 7}, {6, 6}, {7, 5}, {7, 4}, {7, 3},
80 {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}
84 const position hexagon
[7] = {
85 {1, 2}, {1, 5}, {4, 8}, {7, 5}, {7, 2}, {4, 2}, {1, 2}
91 fl_board::fl_board(int X
,int Y
,int W
,int H
,const char *l
)
92 : Fl_Widget (X
, Y
, W
, H
, l
)
117 // I don't know if this is a good solution
118 // lyellow = FL_COLOR_CUBE +
119 // FL_RED_MULTIPLY * 4 +
120 // FL_GREEN_MULTIPLY * 7 +
121 // FL_BLUE_MULTIPLY * 3;
122 lyellow
= fl_color_cube(255 * FL_NUM_RED
/256,
123 255 * FL_NUM_GREEN
/256,
124 200 * FL_NUM_BLUE
/256);
132 fl_board::~fl_board ()
138 emptyll (row
, del_position_f
);
152 ** the fl_board class should only handle one event on its own
153 ** when an FL_PUSH occurs, the widget must check in what state it is
154 ** and where a push can have effect in this state
156 int fl_board::handle (int event
)
158 ::position
* temppos
;
163 /* check what was pushed */
164 if (theboard
== NULL
)
167 if (state
== BOARD_PLAY
)
169 if (checkfrompush ())
176 else if (state
== BOARD_EDIT
)
181 // state = BOARD_NONE
186 if (positionhints
== 0)
189 temppos
= getmousepos ();
191 // mouse was moved to an unrecognized position
194 // stop timer, even if it is not running
195 Fl::remove_timeout (shmpos
, (void *) this);
199 del_position (showpos
);
210 // mouse was moved to a known position
211 // previous position was NULL
215 Fl::add_timeout (.5, shmpos
, (void *) this);
221 // check if mouse was moved to a different position
222 if ((showpos
->row
== temppos
->row
) &&
223 (showpos
->col
== temppos
->col
))
225 del_position (temppos
);
229 // new known position
231 // stop timer, even if it is not running
232 Fl::remove_timeout (shmpos
, (void *) this);
234 del_position (showpos
);
244 Fl::add_timeout (.5, shmpos
, (void *) this);
250 if (positionhints
== 0)
253 Fl::remove_timeout (shmpos
, (void *) this);
257 del_position (showpos
);
276 ** check if one of the from-points was pushed
278 int fl_board::checkfrompush ()
286 pushx
= Fl::event_x ();
287 pushy
= Fl::event_y ();
290 for (i
= 0; i
< 24; i
++)
292 pos2coor (&(fromtable
[i
]), x
, y
);
294 if ((pushx
> (x
- box
)) &&
295 (pushy
> (y
- box
)) &&
296 (pushx
< (x
+ box
)) &&
299 if ((from
== NULL
) ||
300 (from
->col
!= fromtable
[i
].col
) ||
301 (from
->row
!= fromtable
[i
].row
))
303 setfrom (& fromtable
[i
]);
306 else if (gipfpossible
== 1)
308 fromtype
= (fromtype
== 1 ? 0 : 1);
320 ** check if one of the to-points was pushed
322 int fl_board::checktopush ()
330 pushx
= Fl::event_x ();
331 pushy
= Fl::event_y ();
334 for (i
= 0; i
< 18; i
++)
336 pos2coor (&(totable
[i
]), x
, y
);
338 if ((pushx
> (x
- box
)) &&
339 (pushy
> (y
- box
)) &&
340 (pushx
< (x
+ box
)) &&
343 setto (& totable
[i
]);
354 ** check if any point on the board was pushed
356 int fl_board::checkeditpush ()
363 ::position
* temppos
;
366 pushx
= Fl::event_x ();
367 pushy
= Fl::event_y ();
370 temppos
= new_position ();
371 /* check all board positions */
372 for (i
= 1; i
< 8; i
++)
375 for (j
= 2; j
<= b_colsize (i
); j
++)
379 pos2coor (temppos
, x
, y
);
380 if ((pushx
> (x
- box
)) &&
381 (pushy
> (y
- box
)) &&
382 (pushx
< (x
+ box
)) &&
385 if (b_ppiece (theboard
, temppos
) != '.')
387 if ((nboard
= b_edit_piece (theboard
, temppos
, '.'))
396 if ((nboard
= b_edit_piece (theboard
, temppos
, editpiece
))
404 changecountervalues ();
416 position
* fl_board::getmousepos ()
423 ::position
* temppos
;
424 int colsize
[] = {5, 6, 7, 8, 9, 8, 7, 6, 5};
426 pushx
= Fl::event_x ();
427 pushy
= Fl::event_y ();
430 temppos
= new_position ();
432 for (i
= 0; i
< 9; i
++)
435 for (j
= 1; j
<= colsize
[i
]; j
++)
439 pos2coor (temppos
, x
, y
);
440 if ((pushx
> (x
- box
)) &&
441 (pushy
> (y
- box
)) &&
442 (pushx
< (x
+ box
)) &&
455 void fl_board::draw ()
465 ::position
* temppos
;
469 if (!(dam
& FL_DAMAGE_ALL
) &&
470 (dam
& FL_DAMAGE_ANIM
))
471 { /* draw for move-animation */
472 /* maybe things can be speeded up by using clipping */
473 /* calculate clipping-region */
483 fl_clip (clip_x
, clip_y
, clip_w
, clip_h
);
485 /* set everything to background color */
486 // fl_color (Fl_Widget::color());
488 fl_rectf (clip_x
, clip_y
, clip_w
, clip_h
);
492 fl_color (FL_WHITE
); // white
496 for (i
= 0; i
< 7; i
++)
498 pos2coor (&(hexagon
[i
]), x1
, y1
);
500 /* didn't look nice on mswin */
501 if ((i
> 0) && (i
< 4))
510 fl_color (FL_BLACK
); // black
513 for (i
= 0; i
< 21; i
++)
515 pos2coor (&(linetable
[i
][0]), x1
, y1
);
516 pos2coor (&(linetable
[i
][1]), x2
, y2
);
518 /* I have to add 1 to the third parameter, or
519 ** vertical lines don't get drawn on ms windows */
520 if (fl_not_clipped (min (x1
, x2
), min (y1
, y2
),
521 max (x1
, x2
) - min (x1
, x2
) + 1,
522 max (y1
, y2
) - min (y1
, y2
)))
523 fl_line (x1
, y1
, x2
, y2
);
529 for (i
= 0; i
< 24; i
++)
531 pos2coor (&(fromtable
[i
]), x1
, y1
);
532 if (fl_not_clipped (x1
- straal
, y1
- straal
,
533 x1
+ straal
, y1
+ straal
))
536 fl_circle (x1
, y1
, straal
);
540 fl_pie (x1
- straal
, y1
- straal
, diam
, diam
, 0, 360);
545 fl_font (FL_HELVETICA
, base
/12);
547 height
= fl_height () / 2 - fl_descent ();
548 for (i
= 0; i
< 9; i
++)
550 sprintf (tempstr
, "%c1", i
+'a');
551 width
= round (fl_width (tempstr
) / 2);
552 x1
= xoffset
+ round (rowbase
[i
][0] * base
);
553 y1
= yoffset
+ round ((rowbase
[i
][1] - .5 * .25) * base
);
554 fl_draw (tempstr
, x1
- width
, y1
+ height
);
556 nr
= (i
< 5 ? i
+ 5 : 13 - i
);
557 sprintf (tempstr
, "%c%d", i
+'a', nr
);
558 width
= round (fl_width (tempstr
) / 2);
559 y1
= yoffset
+ round ((rowbase
[i
][1] - (nr
+ .5) * .25) * base
);
560 fl_draw (tempstr
, x1
- width
, y1
+ height
);
563 /* draw pieces if there is a board */
564 if (theboard
!= NULL
)
566 temppos
= new_position ();
568 for (i
= 1; i
< 8; i
++)
571 for (j
= 2; j
<= b_colsize (i
); j
++)
574 if (b_ppiece (theboard
, temppos
) != '.')
576 drawpiece (temppos
, b_ppiece (theboard
, temppos
));
582 /* draw from and to (if necessary) */
583 if (state
== BOARD_PLAY
)
587 piece
= b_next_piece (theboard
);
590 piece
= b_otherpiece (piece
);
592 drawpiece (from
, piece
);
597 drawcross (to
->col
, to
->row
);
601 /* draw crosses on row of pieces, if necessary */
606 while ((posp
= (::position
*) llitembynr (row
, counter
)) != NULL
)
608 drawcross (posp
->col
, posp
->row
);
613 if (animlist
!= NULL
)
620 if ((positionhints
!= 0) && (showpos
!= NULL
) && (showflag
== 1))
622 posstr
= postostr (showpos
);
624 pos2coor (showpos
, x1
, y1
);
625 width
= 8 + (int) fl_width (posstr
);
626 height
= 4 + fl_height ();
630 if (fl_not_clipped (x1
, y1
, width
+ 2, height
+ 2))
632 fl_color (FL_DARK2
); // 125,125,125
633 fl_rectf (x1
+ 2, y1
+ 2, width
, height
);
634 fl_color (lyellow
); // 255,255,200
635 fl_rectf (x1
, y1
, width
, height
);
637 fl_rect (x1
, y1
, width
, height
);
638 fl_draw (posstr
, x1
+ 4, y1
+ height
- fl_descent () - 2);
650 void fl_board::drawpiece (::position
* pos
, char piece
)
660 /* don't draw piece if in animation-list */
662 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
666 if ((posp_col (pos
) == posp_col (mpiece
->from
)) &&
667 (posp_row (pos
) == posp_row (mpiece
->from
)))
671 /* calculate position of center of the piece */
672 pos2coor (pos
, x
, y
);
674 drawpiece (x
, y
, piece
);
679 void fl_board::drawpiece (int x
, int y
, char piece
)
686 /* calculate size of piece */
692 if (straal3
> (straal2
- 2))
693 straal3
= straal2
- 2;
695 if (!fl_not_clipped (x
- straal
, y
- straal
, diam
, diam
))
698 if ((piece
== 'o') ||
709 fl_circle (x
, y
, straal
);
714 fl_circle (x
, y
, straal
);
717 if ((piece
== 'O') ||
721 // fl_begin_complex_polygon ();
722 // fl_arc (x, y, straal2, 0, 360);
724 // fl_arc (x, y, straal3, 0, 360);
725 // fl_end_complex_polygon ();
727 fl_circle (x
, y
, straal2
);
735 fl_circle (x
, y
, straal3
);
741 fl_pie (x
- straal
+ 1, y
- straal
+ 1, diam
- 2, diam
- 2, 0, 360);
743 fl_pie (x
- straal
, y
- straal
, diam
- 1, diam
- 1, 0, 360);
747 fl_arc (x
- straal
, y
- straal
, diam
, diam
, 0, 360);
749 if ((piece
== 'O') ||
753 fl_arc (x
- straal2
, y
- straal2
, diam2
, diam2
, 0, 360);
754 fl_arc (x
- straal2
+ 1, y
- straal2
+ 1, diam2
-2, diam2
-2, 0, 360);
762 void fl_board::drawanimpieces (void)
770 int x
, y
, x1
, y1
, x2
, y2
;
773 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
778 /* calculate position of center of the piece */
779 pos2coor (mpiece
->from
, x1
, y1
);
780 pos2coor (mpiece
->to
, x2
, y2
);
781 x
= x1
+ (x2
- x1
) * step
/ maxstep
;
782 y
= y1
+ (y2
- y1
) * step
/ maxstep
;
784 drawpiece (x
, y
, mpiece
->piece
);
789 while ((mpiece
= (struct movepiece
*) llrembynr (animlist
, 1)) != NULL
)
803 void fl_board::drawcross (int col
, int row
)
809 /* calculate position of center of the piece */
812 pos2coor (&temppos
, x
, y
);
816 if (!fl_not_clipped (x
- straal
, y
- straal
, straal
* 2, straal
* 2))
822 ** I draw a lot of lines here to get the impression of a
825 fl_line (x
- straal
, y
- straal
, x
+ straal
, y
+ straal
);
826 fl_line (x
- straal
+ 1, y
- straal
, x
+ straal
, y
+ straal
- 1);
827 fl_line (x
- straal
, y
- straal
+ 1, x
+ straal
- 1, y
+ straal
);
829 fl_line (x
+ straal
, y
- straal
, x
- straal
, y
+ straal
);
830 fl_line (x
+ straal
- 1, y
- straal
, x
- straal
, y
+ straal
- 1);
831 fl_line (x
+ straal
, y
- straal
+ 1, x
- straal
+ 1, y
+ straal
);
837 void fl_board::resize (int x
, int y
, int w
, int h
)
839 Fl_Widget::resize (x
, y
, w
, h
);
845 del_position (showpos
);
860 ** to be used at every resize-event and at class-creation
862 void fl_board::calcsizes ()
867 width
= round (w() / 2.0);
868 height
= round (h() / 2.5);
869 base
= min (width
, height
);
871 xoffset
= round((w() - base
* 2.0) / 2) + x();
872 yoffset
= round((h() - base
* 2.5) / 2) + y();
879 ** calculate screen-coordinates starting from a board-position
881 // solution: Fl_Input_ has a 'position' member function
882 inline void fl_board::pos2coor (const ::position
*pos
, int& x
, int& y
)
884 x
= xoffset
+ round (rowbase
[pos
->col
][0] * base
);
885 y
= yoffset
+ round ((rowbase
[pos
->col
][1] - pos
->row
* .25) * base
);
891 void fl_board::setoutputwidgets (Fl_Output
* wp
, Fl_Output
* wl
,
892 fl_pile
* wpi
, Fl_Output
* bp
,
893 Fl_Output
* bl
, fl_pile
* bpi
,
894 Fl_Output
* from_o
, Fl_Output
* to_o
)
899 wpile
->setcolor ('o');
904 bpile
->setcolor ('x');
909 changecountervalues ();
910 changefromtovalues ();
915 void fl_board::changefromtovalues ()
921 tempstr
= postostr (from
);
922 t_from
->value (tempstr
);
927 t_from
->value (NULL
);
932 tempstr
= postostr (to
);
933 t_to
->value (tempstr
);
947 void fl_board::changecountervalues ()
953 if (theboard
!= NULL
)
955 sprintf (tempstr
, "%d", b_white (theboard
));
956 wpieces
->value (tempstr
);
957 sprintf (tempstr
, "lost: %d", b_white_lost (theboard
));
958 wlost
->value (tempstr
);
959 wpile
->setvalue (b_white (theboard
));
961 sprintf (tempstr
, "%d", b_black (theboard
));
962 bpieces
->value (tempstr
);
963 sprintf (tempstr
, "lost: %d", b_black_lost (theboard
));
964 blost
->value (tempstr
);
965 bpile
->setvalue (b_black (theboard
));
969 wpieces
->value (NULL
);
971 wpile
->setvalue (-1);
972 bpieces
->value (NULL
);
974 bpile
->setvalue (-1);
982 void fl_board::setboard (board
* newboard
)
984 if (b_compare (newboard
, theboard
) == 0)
985 { /* the new is the same as the old */
989 if (theboard
!= NULL
)
993 theboard
= b_copy (newboard
);
995 changecountervalues ();
1002 void fl_board::setfrom (const ::position
* newfrom
)
1008 from
= (::position
*) copy_position ((void *) newfrom
);
1010 changefromtovalues ();
1016 void fl_board::setto (const ::position
* newto
)
1018 if ((newto
!= NULL
) && (from
!= NULL
) && (to
!= NULL
) &&
1019 (execbutton
!= NULL
) &&
1020 (posp_col (to
) == posp_col (newto
)) &&
1021 (posp_row (to
) == posp_row (newto
)))
1023 execbutton
->do_callback ();
1030 to
= (::position
*) copy_position ((void *) newto
);
1032 changefromtovalues ();
1038 void fl_board::seteditpiece (char newpiece
)
1040 editpiece
= newpiece
;
1044 int fl_board::setlostwhite (int val
)
1048 if (theboard
== NULL
)
1051 if ((nboard
= b_edit_lostwhite (theboard
, val
)) != NULL
)
1056 changecountervalues ();
1058 return (b_white_lost (theboard
));
1062 int fl_board::setlostblack (int val
)
1066 if (theboard
== NULL
)
1069 if ((nboard
= b_edit_lostblack (theboard
, val
)) != NULL
)
1074 changecountervalues ();
1076 return (b_black_lost (theboard
));
1080 void fl_board::setstate (int newstate
)
1084 if (state
!= BOARD_PLAY
)
1092 void fl_board::showmousepos ()
1094 if (showpos
!= NULL
)
1104 void shmpos (void * data
)
1106 fl_board
* boardobject
= (fl_board
*) data
;
1108 boardobject
->showmousepos ();
1114 void fl_board::setgipfpossible (int flag
)
1129 void fl_board::setrow (listheader
* rowp
)
1133 emptyll (row
, del_position_f
);
1137 row
= copy_position_row (rowp
);
1146 void fl_board::initanim (int st
, listheader
* al
)
1153 } * mpiece
, * npiece
;
1158 newl
= (listheader
*) malloc (sizeof (listheader
));
1162 while ((mpiece
= (struct movepiece
*) llitembynr (al
, counter
))
1167 npiece
= (struct movepiece
*) malloc (sizeof (struct movepiece
));
1168 npiece
->piece
= mpiece
->piece
;
1169 npiece
->from
= (::position
*) copy_position ((void *) mpiece
->from
);
1170 npiece
->to
= (::position
*) copy_position ((void *) mpiece
->to
);
1172 pushll (newl
, npiece
);
1175 if (animlist
!= NULL
)
1177 while ((mpiece
= (struct movepiece
*) llrembynr (animlist
, 1)) != NULL
)
1179 free (mpiece
->from
);
1192 void fl_board::calc_clipping ()
1204 mpiece
= (struct movepiece
*) llitembynr (animlist
, 1);
1205 pos2coor (mpiece
->from
, x1
, y1
);
1207 while ((mpiece
= (struct movepiece
*) llitembynr (animlist
, counter
))
1211 pos2coor (mpiece
->to
, x2
, y2
);
1215 /* the -2 and +2 are used for a little security */
1216 clip_x
= min (x1
, x2
) - straal
- 2;
1217 clip_y
= min (y1
, y2
) - straal
- 2;
1218 clip_w
= max (x1
, x2
) - clip_x
+ straal
+ 2;
1219 clip_h
= max (y1
, y2
) - clip_y
+ straal
+ 2;