52 #if defined(__cplusplus) && defined(CWDEBUG) 57 #define Dout(channel, output) 58 #define DoutFatal(channel, output) do { } while(0) 64 #include <glib-object.h> 70 #define CONST(name, expr) expr 72 #include "CwChessboard-CONST.h" 73 #define CONST(name, expr) CWCHESSBOARD_CONST_##name 74 #define CWCHESSBOARD_DEFINE_INLINE 1 81 #define CW_CHESSBOARD_FLOATING_PIECE_INVALIDATE_TARGET 0 82 #define CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 1 83 #define CW_CHESSBOARD_EXPOSE_ALWAYS_CLEAR_BACKGROUND 1 // Needed to erase things like menu's. 84 #define CW_CHESSBOARD_EXPOSE_DEBUG 0 86 #define CW_CHESSBOARD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), CW_TYPE_CHESSBOARD, CwChessboardPrivate)) 88 G_DEFINE_TYPE(
CwChessboard, cw_chessboard, GTK_TYPE_DRAWING_AREA);
90 static void cw_chessboard_destroy(GtkObject*
object);
91 static void cw_chessboard_finalize(GObject*
object);
92 static void cw_chessboard_realize(GtkWidget* widget);
93 static void cw_chessboard_unrealize(GtkWidget* widget);
94 static void cw_chessboard_size_request(GtkWidget* widget, GtkRequisition* requisition);
95 static void cw_chessboard_size_allocate(GtkWidget* widget, GtkAllocation* allocation);
96 static gboolean cw_chessboard_expose(GtkWidget* chessboard, GdkEventExpose* event);
97 static gboolean cw_chessboard_motion_notify(GtkWidget* chessboard, GdkEventMotion* event);
98 static gboolean cw_chessboard_default_motion_notify(GtkWidget* chessboard, GdkEventMotion* event);
100 static void recreate_hud_layers(
CwChessboard* chessboard);
101 static void redraw_hud_layer(
CwChessboard* chessboard, guint hud);
106 typedef gint BoardIndex;
110 gint
const squares = 8;
113 gint
const min_sside = 12;
117 guint
const number_of_hud_layers = 2;
119 #define number_of_hud_layers 2 125 inline static BoardIndex convert_colrow2index(gint col, gint row)
127 return col | (row << 3);
134 inline static gint convert_index2column(BoardIndex index)
143 inline static gint convert_index2row(BoardIndex index)
152 inline static void convert_index2xy(
CwChessboard* chessboard, BoardIndex index, gint* x, gint* y)
160 inline static BoardIndex convert_xy2index(
CwChessboard* chessboard, gdouble x, gdouble y)
168 return convert_colrow2index(col, row);
181 static int const pawn = 0;
182 static int const rook = 1;
183 static int const knight = 2;
184 static int const bishop = 3;
185 static int const queen = 4;
186 static int const king = 5;
194 gboolean pointer_device;
200 cairo_surface_t* surface;
211 guint64 has_content[number_of_hud_layers];
213 typedef struct _Arrow Arrow;
221 CairoColor dark_square_color;
222 guint32 dark_square_color_pixel;
223 CairoColor light_square_color;
224 guint32 light_square_color_pixel;
225 CairoColor board_border_color;
226 guint32 board_border_color_pixel;
227 CairoColor white_piece_fill_color;
228 guint32 white_piece_fill_color_pixel;
229 CairoColor white_piece_line_color;
230 guint32 white_piece_line_color_pixel;
231 CairoColor black_piece_fill_color;
232 guint32 black_piece_fill_color_pixel;
233 CairoColor black_piece_line_color;
234 guint32 black_piece_line_color_pixel;
235 GdkColor widget_background_color;
236 CairoColor color_palet[31];
237 guint32 allocated_colors_mask;
238 CairoColor cursor_color;
239 guint32 cursor_color_pixel;
242 gboolean draw_border;
244 gboolean draw_turn_indicators;
245 gboolean active_turn_indicator;
246 gboolean has_hud_layer[number_of_hud_layers];
247 gdouble marker_thickness;
248 gboolean marker_below;
249 gdouble cursor_thickness;
250 gboolean show_cursor;
255 gint top_left_pixmap_x;
256 gint top_left_pixmap_y;
257 gint bottom_right_pixmap_x;
258 gint bottom_right_pixmap_y;
259 gint pixmap_top_left_a8_x;
260 gint pixmap_top_left_a8_y;
261 GdkRegion* chessboard_region;
262 gint marker_thickness_px;
263 gint cursor_thickness_px;
270 SquareCache piece_pixmap[12];
271 cairo_surface_t* hud_layer_surface[number_of_hud_layers];
272 gint64 hud_has_content[number_of_hud_layers];
273 gint64 hud_need_redraw[number_of_hud_layers];
274 SquareCache hatching_pixmap;
277 gint64 need_redraw_invalidated;
280 gsize number_of_floating_pieces;
281 FloatingPiece floating_piece[32];
282 gint floating_piece_handle;
283 gboolean redraw_background;
296 return (code & piece_mask) == 0;
302 return ((code & piece_mask) >> 1) - 1;
308 return (code & piece_color_mask) - 2;
314 return (code & color_mask) != 0;
319 return (
unsigned char)((piece << 1) | (white ? 3 : 2));
324 return (code & bghandle_mask) >> 4;
330 return bghandle << 4;
335 return (code & mahandle_mask) >> 9;
341 return mahandle << 9;
344 static inline gboolean is_inside_board(gint col, gint row)
346 return !((col | row) & ~0x7);
352 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(chessboard_class);
353 GtkObjectClass* object_class = GTK_OBJECT_CLASS(widget_class);
354 GObjectClass* gobject_class = G_OBJECT_CLASS(object_class);
358 gobject_class->finalize = cw_chessboard_finalize;
360 object_class->destroy = cw_chessboard_destroy;
362 widget_class->expose_event = cw_chessboard_expose;
363 widget_class->motion_notify_event = cw_chessboard_default_motion_notify;
365 widget_class->realize = cw_chessboard_realize;
366 widget_class->size_request = cw_chessboard_size_request;
367 widget_class->size_allocate = cw_chessboard_size_allocate;
368 widget_class->unrealize = cw_chessboard_unrealize;
385 static void cw_chessboard_destroy(GtkObject*
object)
387 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_destroy(" <<
object <<
")");
388 GTK_OBJECT_CLASS(cw_chessboard_parent_class)->destroy(
object);
392 static void cw_chessboard_init(
CwChessboard* chessboard)
394 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_init(" << chessboard <<
")");
397 GdkColormap* colormap = gtk_widget_get_colormap(GTK_WIDGET(chessboard));
400 chessboard->priv = priv;
402 priv->draw_border = TRUE;
403 priv->flip_board = FALSE;
404 priv->draw_turn_indicators = TRUE;
405 priv->active_turn_indicator = TRUE;
406 memset(priv->piece_pixmap, 0,
sizeof(priv->piece_pixmap));
407 memset(priv->has_hud_layer, 0,
sizeof(priv->has_hud_layer));
408 priv->hatching_pixmap.surface = NULL;
410 priv->marker_thickness = 0.08;
411 priv->marker_below = FALSE;
412 priv->cursor_thickness = 0.04;
413 priv->show_cursor = FALSE;
414 priv->cursor_col = -1;
415 priv->cursor_row = -1;
416 * (gint*)(&chessboard->
sside) = 0;
417 memset(priv->board_codes, 0,
sizeof(priv->board_codes));
418 priv->number_of_floating_pieces = 0;
419 priv->floating_piece_handle = -1;
420 memset(priv->floating_piece, 0,
sizeof(priv->floating_piece));
421 priv->allocated_colors_mask = 0;
423 priv->top_left_pixmap_x = 0;
424 priv->top_left_pixmap_y = 0;
425 priv->bottom_right_pixmap_x = 0;
426 priv->bottom_right_pixmap_y = 0;
428 priv->chessboard_region = NULL;
429 memset(priv->hud_layer_surface, 0,
sizeof(priv->hud_layer_surface));
430 priv->arrows = g_ptr_array_new();
466 gushort
const dark_square_red = 45875;
467 gushort
const dark_square_green = 58981;
468 gushort
const dark_square_blue = 45875;
471 gushort
const light_square_red = 65535;
472 gushort
const light_square_green = 65535;
473 gushort
const light_square_blue = 58981;
479 GdkColor dark_square_color;
480 GdkColor light_square_color;
483 for (
double x = 0.0; x <= 1.0; x += 0.01)
485 dark_square_color.red = (gushort)((1.0 - x) * dark_square_red);
486 dark_square_color.green = (gushort)((1.0 - x) * dark_square_green);
487 dark_square_color.blue = (gushort)((1.0 - x) * dark_square_blue);
488 if (!gdk_colormap_alloc_color(colormap,& dark_square_color, FALSE, TRUE))
489 DoutFatal(dc::fatal,
"gdk_colormap_alloc_color failed to allocate dark_square_color (" <<
490 dark_square_color.red <<
", " <<
491 dark_square_color.green <<
", " <<
492 dark_square_color.blue <<
")");
494 light_square_color.red = light_square_red + (gushort)(x * (65535 - light_square_red));
495 light_square_color.green = light_square_green + (gushort)(x * (65535 - light_square_green));
496 light_square_color.blue = light_square_blue + (gushort)(x * (65535 - light_square_blue));
497 if (!gdk_colormap_alloc_color(colormap,& light_square_color, FALSE, TRUE))
498 DoutFatal(dc::fatal,
"gdk_colormap_alloc_color failed to allocate light_square_color (" <<
499 light_square_color.red <<
", " <<
500 light_square_color.green <<
", " <<
501 light_square_color.blue <<
")");
503 if (dark_square_color.red != light_square_color.red ||
504 dark_square_color.green != light_square_color.green ||
505 dark_square_color.blue != light_square_color.blue)
514 priv->widget_background_color = light_square_color;
518 priv->white_piece_fill_color.red = 1.0;
519 priv->white_piece_fill_color.green = 1.0;
520 priv->white_piece_fill_color.blue = 1.0;
522 priv->white_piece_line_color.red = 0.0;
523 priv->white_piece_line_color.green = 0.0;
524 priv->white_piece_line_color.blue = 0.0;
526 priv->black_piece_fill_color.red = 0.0;
527 priv->black_piece_fill_color.green = 0.0;
528 priv->black_piece_fill_color.blue = 0.0;
530 priv->black_piece_line_color.red = 1.0;
531 priv->black_piece_line_color.green = 1.0;
532 priv->black_piece_line_color.blue = 1.0;
534 priv->cursor_color.red = 1.0;
535 priv->cursor_color.green = 0.0;
536 priv->cursor_color.blue = 0.0;
539 gtk_widget_set_double_buffered(GTK_WIDGET(chessboard), FALSE);
541 gtk_widget_add_events(GTK_WIDGET(chessboard),
542 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
543 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
546 g_signal_connect(G_OBJECT(chessboard),
"motion-notify-event", G_CALLBACK(cw_chessboard_motion_notify), NULL);
549 static void cw_chessboard_finalize(GObject*
object)
551 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_finalize(" <<
object <<
")");
553 g_ptr_array_free(chessboard->priv->arrows, TRUE);
554 G_OBJECT_CLASS(cw_chessboard_parent_class)->finalize(
object);
559 if (GTK_WIDGET_REALIZED(chessboard))
562 GdkWindow* window = GTK_WIDGET(chessboard)->window;
563 GdkRectangle pixmap_rect;
564 pixmap_rect.x = priv->top_left_pixmap_x;
565 pixmap_rect.y = priv->top_left_pixmap_y;
566 pixmap_rect.width = priv->bottom_right_pixmap_x - priv->top_left_pixmap_x;
567 pixmap_rect.height = priv->bottom_right_pixmap_y - priv->top_left_pixmap_y;
568 GdkRegion* border_region = gdk_region_rectangle(&pixmap_rect);
569 gdk_region_subtract(border_region, priv->chessboard_region);
570 gdk_window_invalidate_region(window, border_region, FALSE);
571 gdk_region_destroy(border_region);
575 static void invalidate_turn_indicators(
CwChessboard* chessboard)
577 if (GTK_WIDGET_REALIZED(chessboard))
581 gint
const border_width = priv->border_width;
582 gint
const border_shadow_width = 2;
583 gint
const edge_width = border_width - border_shadow_width - 1;
584 gint
const side = squares * priv->sside;
586 double const factor = 0.085786;
587 int const dx = (int)ceil((edge_width + 1) * factor);
589 GdkRectangle top_indicator_rect, bottom_indicator_rect;
590 top_indicator_rect.x = priv->top_left_pixmap_x + priv->pixmap_top_left_a8_x + side + 1 - dx;
591 top_indicator_rect.y = priv->top_left_pixmap_y + priv->pixmap_top_left_a8_y - 1 - edge_width;
592 top_indicator_rect.width = edge_width + dx;
593 top_indicator_rect.height = edge_width;
594 GdkRegion* indicator_region = gdk_region_rectangle(&top_indicator_rect);
595 bottom_indicator_rect.x = top_indicator_rect.x;
596 bottom_indicator_rect.y = top_indicator_rect.y + edge_width + side + 2;
597 bottom_indicator_rect.width = edge_width + dx;
598 bottom_indicator_rect.height = edge_width;
599 gdk_region_union_with_rect(indicator_region,& bottom_indicator_rect);
600 top_indicator_rect.x += dx;
601 top_indicator_rect.y += edge_width;
602 top_indicator_rect.width = edge_width;
603 top_indicator_rect.height = dx;
604 gdk_region_union_with_rect(indicator_region,& top_indicator_rect);
605 bottom_indicator_rect.x += dx;
606 bottom_indicator_rect.y -= dx;
607 bottom_indicator_rect.width = edge_width;
608 bottom_indicator_rect.height = dx;
609 gdk_region_union_with_rect(indicator_region,& bottom_indicator_rect);
610 gdk_window_invalidate_region(GTK_WIDGET(chessboard)->window, indicator_region, FALSE);
611 gdk_region_destroy(indicator_region);
615 #if 0 // Not currently used anywhere. 616 static void invalidate_background(
CwChessboard* chessboard)
618 if (GTK_WIDGET_REALIZED(chessboard))
621 GdkWindow* window = GTK_WIDGET(chessboard)->window;
622 GdkRegion* background_region = gdk_drawable_get_clip_region(window);
623 gdk_region_subtract(background_region, priv->chessboard_region);
624 gdk_window_invalidate_region(window, background_region, FALSE);
625 gdk_region_destroy(background_region);
626 priv->redraw_background = TRUE;
631 static void invalidate_square(
CwChessboard* chessboard, gint col, gint row)
634 guint64 redraw_mask = 1;
635 redraw_mask <<= convert_colrow2index(col, row);
637 if (!(priv->need_redraw_invalidated & redraw_mask))
639 if (GTK_WIDGET_REALIZED(chessboard))
642 rect.width = priv->sside;
643 rect.height = priv->sside;
645 gdk_window_invalidate_rect(GTK_WIDGET(chessboard)->window,& rect, FALSE);
646 priv->need_redraw_invalidated |= redraw_mask;
649 priv->need_redraw |= redraw_mask;
656 if (GTK_WIDGET_REALIZED(chessboard))
658 gdk_window_invalidate_region(GTK_WIDGET(chessboard)->window, priv->chessboard_region, FALSE);
659 priv->need_redraw_invalidated = (guint64)-1;
662 priv->need_redraw = (guint64)-1;
665 static void invalidate_markers(
CwChessboard* chessboard)
668 for (gint row = 0; row < squares; ++row)
669 for (gint col = 0; col < squares; ++col)
670 if (convert_code2mahandle(priv->board_codes[convert_colrow2index(col, row)]) != 0)
671 invalidate_square(chessboard, col, row);
677 if (priv->show_cursor && is_inside_board(priv->cursor_col, priv->cursor_row))
678 invalidate_square(chessboard, priv->cursor_col, priv->cursor_row);
681 static void update_cursor_position(
CwChessboard* chessboard, gdouble x, gdouble y, gboolean forced)
686 gboolean cursor_moved = (col != priv->cursor_col || row != priv->cursor_row);
687 gboolean was_inside_board = is_inside_board(priv->cursor_col, priv->cursor_row);
688 gboolean inside_board = is_inside_board(col, row);
689 if (cursor_moved || forced)
693 if (CW_CHESSBOARD_GET_CLASS(chessboard)->cursor_entered_square)
695 if (was_inside_board)
696 CW_CHESSBOARD_GET_CLASS(chessboard)->cursor_entered_square(chessboard, priv->cursor_col, priv->cursor_row, col, row);
698 CW_CHESSBOARD_GET_CLASS(chessboard)->cursor_entered_square(chessboard, -1, -1, col, row);
700 if (priv->show_cursor)
701 invalidate_square(chessboard, col, row);
703 else if (was_inside_board && CW_CHESSBOARD_GET_CLASS(chessboard)->cursor_left_chessboard)
704 CW_CHESSBOARD_GET_CLASS(chessboard)->cursor_left_chessboard(chessboard, priv->cursor_col, priv->cursor_row);
705 if (priv->show_cursor && was_inside_board)
706 invalidate_square(chessboard, priv->cursor_col, priv->cursor_row);
707 priv->cursor_col = col;
708 priv->cursor_row = row;
710 if (priv->show_cursor && !priv->need_redraw_invalidated)
713 Dout(dc::cwchessboardwidget,
"Calling gdk_window_get_pointer()");
714 gdk_window_get_pointer(GTK_WIDGET(chessboard)->window, NULL, NULL, NULL);
721 cairo_t* cr = priv->cr;
723 gint
const pixmap_width = priv->bottom_right_pixmap_x - priv->top_left_pixmap_x;
724 gint
const pixmap_height = priv->bottom_right_pixmap_y - priv->top_left_pixmap_y;
725 gint
const side = squares * priv->sside;
728 if (priv->pixmap_top_left_a8_x != 0)
729 cairo_rectangle(cr, 0, 0, priv->pixmap_top_left_a8_x, pixmap_height);
730 if (pixmap_width - priv->pixmap_top_left_a8_x - side != 0)
731 cairo_rectangle(cr, priv->pixmap_top_left_a8_x + side, 0,
732 pixmap_width - priv->pixmap_top_left_a8_x - side, pixmap_height);
733 if (priv->pixmap_top_left_a8_y != 0)
734 cairo_rectangle(cr, 0, 0, pixmap_width, priv->pixmap_top_left_a8_y);
735 if (pixmap_height - priv->pixmap_top_left_a8_y - side != 0)
736 cairo_rectangle(cr, 0, priv->pixmap_top_left_a8_y + side,
737 pixmap_width, pixmap_height - priv->pixmap_top_left_a8_y - side);
738 cairo_set_source_rgb(cr, priv->widget_background_color.red / 65535.0,
739 priv->widget_background_color.green / 65535.0, priv->widget_background_color.blue / 65535.0);
743 if (priv->border_width)
744 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_border(chessboard);
747 invalidate_border(chessboard);
753 cairo_t* cr = priv->cr;
755 gint
const border_width = priv->border_width;
756 gint
const border_shadow_width = 2;
757 gint
const edge_width = border_width - border_shadow_width - 1;
758 gint
const side = squares * priv->sside;
762 cairo_translate(cr, priv->pixmap_top_left_a8_x - border_width, priv->pixmap_top_left_a8_y - border_width);
764 cairo_set_source_rgb(cr, 0, 0, 0);
765 cairo_set_line_width(cr, 1.0);
766 cairo_set_source_rgb(cr, priv->board_border_color.red * 0.5, priv->board_border_color.green * 0.5, priv->board_border_color.blue * 0.5);
767 cairo_move_to(cr, side + border_width + 0.5, border_width - 0.5);
768 cairo_line_to(cr, border_width - 0.5, border_width - 0.5);
769 cairo_line_to(cr, border_width - 0.5, side + border_width + 0.5);
771 cairo_set_source_rgb(cr, (1.0 + priv->board_border_color.red) * 0.5, (1.0 + priv->board_border_color.green) * 0.5, (1.0 + priv->board_border_color.blue) * 0.5);
772 cairo_move_to(cr, border_width - 0.5, side + border_width + 0.5);
773 cairo_line_to(cr, side + border_width + 0.5, side + border_width + 0.5);
774 cairo_line_to(cr, side + border_width + 0.5, border_width - 0.5);
777 cairo_set_source_rgb(cr, priv->board_border_color.red, priv->board_border_color.green, priv->board_border_color.blue);
778 cairo_set_line_width(cr, edge_width);
779 cairo_rectangle(cr, border_shadow_width + edge_width * 0.5, border_shadow_width + edge_width * 0.5, side + edge_width + 2, side + edge_width + 2);
782 cairo_set_source_rgb(cr, (1.0 + priv->board_border_color.red) * 0.5, (1.0 + priv->board_border_color.green) * 0.5, (1.0 + priv->board_border_color.blue) * 0.5);
783 cairo_move_to(cr, 0, 0);
784 cairo_line_to(cr, 0, side + 2 * border_width);
785 cairo_rel_line_to(cr, border_shadow_width, -border_shadow_width);
786 cairo_rel_line_to(cr, 0, -(side + 2 + 2 * edge_width));
787 cairo_rel_line_to(cr, side + 2 + 2 * edge_width, 0);
788 cairo_rel_line_to(cr, border_shadow_width, -border_shadow_width);
789 cairo_close_path(cr);
791 cairo_set_source_rgb(cr, priv->board_border_color.red * 0.5, priv->board_border_color.green * 0.5, priv->board_border_color.blue * 0.5);
792 cairo_move_to(cr, side + 2 * border_width, side + 2 * border_width);
793 cairo_line_to(cr, side + 2 * border_width, 0);
794 cairo_rel_line_to(cr, -border_shadow_width, border_shadow_width);
795 cairo_rel_line_to(cr, 0, side + 2 + 2 * edge_width);
796 cairo_rel_line_to(cr, -(side + 2 + 2 * edge_width), 0);
797 cairo_rel_line_to(cr, -border_shadow_width, border_shadow_width);
798 cairo_close_path(cr);
801 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
802 PangoLayout* layout = pango_cairo_create_layout(cr);
803 PangoFontDescription* desc = pango_font_description_from_string(
"Sans Bold 14");
804 gint font_pixels = (edge_width > 14) ? MAX(14, edge_width * 0.66) : edge_width;
805 pango_font_description_set_absolute_size(desc, MAX(font_pixels, 7) * PANGO_SCALE);
806 pango_layout_set_font_description(layout, desc);
807 pango_font_description_free(desc);
808 char c[2] = { 0, 0 };
809 for (
int col = 0; col < 8; ++col)
812 pango_layout_set_text(layout, c, -1);
814 pango_layout_get_size(layout,& width,& height);
815 cairo_move_to(cr, border_width + ((priv->flip_board ? 7 - col : col) + 0.5) * priv->sside - ((
double)width / PANGO_SCALE) / 2,
816 side + 1.5 * border_width - ((
double)height / PANGO_SCALE) / 2);
817 pango_cairo_show_layout(cr, layout);
819 for (
int row = 0; row < 8; ++row)
822 pango_layout_set_text(layout, c, -1);
824 pango_layout_get_size(layout,& width,& height);
825 cairo_move_to(cr, border_width / 2 - ((
double)width / PANGO_SCALE) / 2,
826 border_width + ((priv->flip_board ? row : 7 - row) + 0.5) * priv->sside - ((
double)height / PANGO_SCALE) / 2);
827 pango_cairo_show_layout(cr, layout);
829 g_object_unref(layout);
834 if (priv->draw_turn_indicators)
835 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_turn_indicator(chessboard, priv->active_turn_indicator, TRUE);
841 cairo_t* cr = priv->cr;
843 gint
const border_width = priv->border_width;
844 gint
const border_shadow_width = 2;
845 gint
const edge_width = border_width - border_shadow_width - 1;
846 gint
const side = squares * priv->sside;
850 cairo_translate(cr, priv->pixmap_top_left_a8_x + side + 1,
851 priv->pixmap_top_left_a8_y - border_width + border_shadow_width + ((white != priv->flip_board) ? side + edge_width + 2 : 0));
853 double const factor = 0.085786;
857 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
859 cairo_set_source_rgb(cr, 0, 0, 0);
860 cairo_arc(cr, edge_width * 0.5 - MAX((edge_width + 1) * factor - 1, 0),
861 edge_width * 0.5 - (edge_width + 1) * ((white != priv->flip_board) ? factor : -factor), edge_width * 0.5, 0, 2 * M_PI);
866 gboolean top = (white == priv->flip_board);
867 double dir = top ? 1.0 : -1.0;
868 cairo_set_source_rgb(cr, priv->board_border_color.red, priv->board_border_color.green, priv->board_border_color.blue);
869 cairo_move_to(cr, 0, top ? edge_width : 0);
870 cairo_rel_line_to(cr, 0, dir * ((edge_width + 1) * factor + 1));
871 cairo_rel_line_to(cr, edge_width, 0);
872 cairo_line_to(cr, edge_width, top ? 0 : edge_width);
873 cairo_rel_line_to(cr, -(edge_width + (edge_width + 1) * factor + 1), 0);
874 cairo_rel_line_to(cr, 0, dir * edge_width);
875 cairo_close_path(cr);
884 static void redraw_square(
CwChessboard* chessboard, gint index)
887 cairo_t* cr = priv->cr;
892 gint col = convert_index2column(index);
893 gint row = convert_index2row(index);
894 gint sx = priv->pixmap_top_left_a8_x + (priv->flip_board ? 7 - col : col) * priv->sside;
895 gint sy = priv->pixmap_top_left_a8_y + (squares - 1 - (priv->flip_board ? 7 - row : row)) * priv->sside;
897 Dout(dc::cwchessboardwidget,
"Calling redraw_square(" << chessboard <<
", " << index <<
")" <<
898 " with Board Code: " << (
int)code);
901 cairo_rectangle(cr, sx, sy, priv->sside, priv->sside);
903 cairo_set_source_rgb(cr,
904 priv->color_palet[bghandle - 1].red,
905 priv->color_palet[bghandle - 1].green,
906 priv->color_palet[bghandle - 1].blue);
907 else if (((col + row) & 1))
908 cairo_set_source_rgb(cr,
909 priv->light_square_color.red,
910 priv->light_square_color.green,
911 priv->light_square_color.blue);
913 cairo_set_source_rgb(cr,
914 priv->dark_square_color.red,
915 priv->dark_square_color.green,
916 priv->dark_square_color.blue);
917 if (!mahandle || !priv->marker_below)
921 cairo_fill_preserve(cr);
923 cairo_rectangle(cr, sx + priv->marker_thickness_px, sy + priv->marker_thickness_px,
924 priv->sside - 2 * priv->marker_thickness_px, priv->sside - 2 * priv->marker_thickness_px);
925 cairo_fill_rule_t prev_fill_rule = cairo_get_fill_rule(cr);
926 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
927 cairo_set_source_rgb(cr,
928 priv->color_palet[mahandle - 1].red,
929 priv->color_palet[mahandle - 1].green,
930 priv->color_palet[mahandle - 1].blue);
932 cairo_set_fill_rule(cr, prev_fill_rule);
939 if ((priv->hud_has_content[0] & bit))
941 cairo_set_source_surface(cr, priv->hud_layer_surface[0], priv->pixmap_top_left_a8_x, priv->pixmap_top_left_a8_y);
942 cairo_rectangle(cr, sx, sy, priv->sside, priv->sside);
947 if (mahandle && !priv->marker_below)
949 cairo_rectangle(cr, sx, sy, priv->sside, priv->sside);
950 cairo_rectangle(cr, sx + priv->marker_thickness_px, sy + priv->marker_thickness_px,
951 priv->sside - 2 * priv->marker_thickness_px, priv->sside - 2 * priv->marker_thickness_px);
952 cairo_fill_rule_t prev_fill_rule = cairo_get_fill_rule(cr);
953 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
954 cairo_set_source_rgb(cr,
955 priv->color_palet[mahandle - 1].red,
956 priv->color_palet[mahandle - 1].green,
957 priv->color_palet[mahandle - 1].blue);
959 cairo_set_fill_rule(cr, prev_fill_rule);
962 if (priv->show_cursor && priv->cursor_col == col && priv->cursor_row == row)
964 cairo_rectangle(cr, sx, sy, priv->sside, priv->sside);
965 cairo_rectangle(cr, sx + priv->cursor_thickness_px, sy + priv->cursor_thickness_px,
966 priv->sside - 2 * priv->cursor_thickness_px, priv->sside - 2 * priv->cursor_thickness_px);
967 cairo_fill_rule_t prev_fill_rule = cairo_get_fill_rule(cr);
968 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
969 cairo_set_source_rgb(cr,
970 priv->cursor_color.red,
971 priv->cursor_color.green,
972 priv->cursor_color.blue);
974 cairo_set_fill_rule(cr, prev_fill_rule);
978 if (!is_empty_square(code))
980 cairo_set_source_surface(cr, priv->piece_pixmap[convert_code2piece_pixmap_index(code)].surface, sx, sy);
985 if ((priv->hud_has_content[1] & bit))
987 cairo_set_source_surface(cr, priv->hud_layer_surface[1], priv->pixmap_top_left_a8_x, priv->pixmap_top_left_a8_y);
988 cairo_rectangle(cr, sx, sy, priv->sside, priv->sside);
996 for (
int i = 0; i < 12; ++i)
998 if (priv->piece_pixmap[i].surface)
999 cairo_surface_destroy(priv->piece_pixmap[i].surface);
1000 priv->piece_pixmap[i].surface =
1001 cairo_surface_create_similar(cairo_get_target(priv->cr),
1002 CAIRO_CONTENT_COLOR_ALPHA, priv->sside, priv->sside);
1003 Dout(dc::cwchessboardwidget|continued_cf,
"(Re)drawing piece cache " << i <<
"... ");
1004 cairo_t* cr = cairo_create(priv->piece_pixmap[i].surface);
1005 unsigned char code = (
unsigned char)(i + 2);
1006 cairo_rectangle(cr, 0, 0, priv->sside, priv->sside);
1008 CW_CHESSBOARD_GET_CLASS(chessboard)->
1009 draw_piece[convert_code2piece(code)] (chessboard,
1014 is_white_piece(code));
1016 Dout(dc::finish,
"done");
1018 invalidate_board(chessboard);
1023 static void redraw_pixmap(GtkWidget* widget)
1029 gint
const max_total_side = MIN(widget->allocation.width, widget->allocation.height);
1032 gint sside = MAX(min_sside, max_total_side / squares);
1033 priv->border_width = 0;
1035 if (priv->draw_border)
1045 priv->border_width = CW_CHESSBOARD_GET_CLASS(chessboard)->calc_board_border_width(chessboard, sside);
1047 while (sside > min_sside && squares * sside + 2 * priv->border_width > max_total_side);
1052 gint
const side = squares * sside;
1054 gint
const total_side = side + 2 * priv->border_width;
1057 gint pixmap_width = total_side;
1058 gint pixmap_height = total_side;
1059 if (widget->allocation.width < widget->allocation.height)
1060 pixmap_width = widget->allocation.width;
1062 pixmap_height = widget->allocation.height;
1065 gint old_pixmap_width = priv->bottom_right_pixmap_x - priv->top_left_pixmap_x;
1066 gint old_pixmap_height = priv->bottom_right_pixmap_y - priv->top_left_pixmap_y;
1068 priv->top_left_pixmap_x = ((widget->allocation.width - pixmap_width) & ~1) / 2;
1069 priv->top_left_pixmap_y = ((widget->allocation.height - pixmap_height) & ~1) / 2;
1070 priv->bottom_right_pixmap_x = priv->top_left_pixmap_x + pixmap_width;
1071 priv->bottom_right_pixmap_y = priv->top_left_pixmap_y + pixmap_height;
1072 g_assert(priv->top_left_pixmap_x == 0 || priv->top_left_pixmap_y == 0);
1075 * (gint*)(&chessboard->
top_left_a1_x) = ((widget->allocation.width - side) & ~1) / 2;
1076 * (gint*)(&chessboard->
top_left_a1_y) = ((widget->allocation.height - side) & ~1) / 2 + side - sside;
1079 priv->pixmap_top_left_a8_x = chessboard->
top_left_a1_x - priv->top_left_pixmap_x;
1080 priv->pixmap_top_left_a8_y = chessboard->
top_left_a1_y + sside - side - priv->top_left_pixmap_y;
1084 rect.x = priv->top_left_pixmap_x + priv->pixmap_top_left_a8_x;
1085 rect.y = priv->top_left_pixmap_y + priv->pixmap_top_left_a8_y;
1086 rect.width = squares * sside;
1087 rect.height = squares * sside;
1088 if (priv->chessboard_region)
1089 gdk_region_destroy(priv->chessboard_region);
1090 priv->chessboard_region = gdk_region_rectangle(&rect);
1092 Dout(dc::cwchessboardwidget,
"widget size is (" << widget->allocation.width <<
", " << widget->allocation.height <<
")");
1093 Dout(dc::cwchessboardwidget,
"border width is " << priv->border_width <<
1094 "; " << squares <<
'x' << squares <<
" squares with side " << sside);
1095 Dout(dc::cwchessboardwidget,
"pixmap at (" << priv->top_left_pixmap_x <<
", " << priv->top_left_pixmap_y <<
") with size (" <<
1096 pixmap_width <<
", " << pixmap_height <<
")");
1097 Dout(dc::cwchessboardwidget,
"a8 offset within pixmap is (" <<
1098 priv->pixmap_top_left_a8_x <<
", " << priv->pixmap_top_left_a8_y <<
")");
1102 gdk_window_invalidate_rect(widget->window,& widget->allocation, FALSE);
1103 priv->need_redraw_invalidated = (guint64)-1;
1105 if (old_pixmap_width == pixmap_width && old_pixmap_height == pixmap_height)
1109 cairo_destroy(priv->cr);
1111 g_object_unref(priv->pixmap);
1114 priv->pixmap = gdk_pixmap_new(widget->window, pixmap_width, pixmap_height, -1);
1117 priv->cr = gdk_cairo_create(priv->pixmap);
1122 if (priv->sside != sside)
1125 * (gint*)(&chessboard->
sside) = priv->sside = sside;
1128 if (priv->hatching_pixmap.surface)
1129 cairo_surface_destroy(priv->hatching_pixmap.surface);
1130 priv->hatching_pixmap.surface = NULL;
1133 redraw_pieces(chessboard);
1136 priv->marker_thickness_px = MAX(1, MIN((gint)round(priv->marker_thickness * sside), sside / 2));
1137 Dout(dc::cwchessboardwidget,
"Marker thickness set to " << priv->marker_thickness_px);
1140 priv->cursor_thickness_px = MAX(1, MIN((gint)round(priv->cursor_thickness * sside), sside / 2));
1141 Dout(dc::cwchessboardwidget,
"Cursor thickness set to " << priv->cursor_thickness_px);
1144 Dout(dc::cwchessboardwidget|continued_cf,
"(Re)creating HUD layers... ");
1145 recreate_hud_layers(chessboard);
1146 Dout(dc::finish,
"done");
1149 redraw_border(chessboard);
1152 static void cw_chessboard_size_request(GtkWidget* widget, GtkRequisition* requisition)
1154 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_size_request(" <<
")");
1160 gint min_border_width = 0;
1161 if (priv->draw_border)
1162 min_border_width = 2 * CW_CHESSBOARD_GET_CLASS(chessboard)->calc_board_border_width(chessboard, min_sside);
1163 requisition->width = requisition->height = squares * min_sside + min_border_width;
1166 static void cw_chessboard_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
1168 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_size_allocate(" << widget <<
", " << allocation <<
")");
1169 widget->allocation =* allocation;
1170 if (GTK_WIDGET_REALIZED(widget))
1172 gdk_window_move_resize(widget->window,
1173 allocation->x, allocation->y,
1174 allocation->width, allocation->height);
1175 redraw_pixmap(widget);
1178 chessboard->priv->redraw_background = TRUE;
1181 static void cw_chessboard_realize(GtkWidget* widget)
1183 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_realize(" << widget <<
")");
1185 GTK_WIDGET_CLASS(cw_chessboard_parent_class)->realize(widget);
1186 redraw_pixmap(widget);
1188 gdk_window_set_background(widget->window,& chessboard->priv->widget_background_color);
1191 static void cw_chessboard_unrealize(GtkWidget* widget)
1193 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_unrealize(" << widget <<
")");
1196 for (
int i = 0; i < 12; ++i)
1198 if (priv->piece_pixmap[i].surface)
1199 cairo_surface_destroy(priv->piece_pixmap[i].surface);
1200 priv->piece_pixmap[i].surface = NULL;
1202 if (priv->hatching_pixmap.surface)
1203 cairo_surface_destroy(priv->hatching_pixmap.surface);
1204 priv->hatching_pixmap.surface = NULL;
1205 gdk_region_destroy(priv->chessboard_region);
1206 priv->chessboard_region = NULL;
1207 for (guint hud = 0; hud < G_N_ELEMENTS(priv->hud_layer_surface); ++hud)
1208 cairo_surface_destroy(priv->hud_layer_surface[hud]);
1209 memset(priv->hud_layer_surface, 0,
sizeof(priv->hud_layer_surface));
1210 cairo_destroy(priv->cr);
1212 g_object_unref(priv->pixmap);
1213 priv->pixmap = NULL;
1215 priv->top_left_pixmap_x = 0;
1216 priv->top_left_pixmap_y = 0;
1217 priv->bottom_right_pixmap_x = 0;
1218 priv->bottom_right_pixmap_y = 0;
1219 GTK_WIDGET_CLASS(cw_chessboard_parent_class)->unrealize(widget);
1224 static gboolean cw_chessboard_expose(GtkWidget* widget, GdkEventExpose* event)
1226 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_expose(" << widget <<
", " << event <<
")");
1230 GdkRegion* region =
event->region;
1232 #if CW_CHESSBOARD_EXPOSE_DEBUG 1233 gdk_window_clear(widget->window);
1237 for (guint hud = 0; hud < G_N_ELEMENTS(priv->hud_need_redraw); ++hud)
1238 if (priv->hud_need_redraw[hud])
1239 redraw_hud_layer(chessboard, hud);
1242 guint64 redraw_mask = 1;
1243 for (gint i = 0; i < 64; ++i, redraw_mask <<= 1)
1244 if (((priv->need_redraw | priv->need_redraw_invalidated) & redraw_mask))
1245 redraw_square(chessboard, i);
1246 priv->need_redraw_invalidated = 0;
1247 priv->need_redraw = 0;
1249 #if CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 1251 if (priv->number_of_floating_pieces)
1253 cairo_save(priv->cr);
1254 cairo_rectangle(priv->cr, priv->pixmap_top_left_a8_x, priv->pixmap_top_left_a8_y,
1255 squares * priv->sside, squares * priv->sside);
1256 cairo_clip(priv->cr);
1257 for (gsize i = 0; i < priv->number_of_floating_pieces; ++i)
1258 if (priv->floating_piece[i].moved)
1260 cairo_set_source_surface(priv->cr,
1261 priv->piece_pixmap[convert_code2piece_pixmap_index(priv->floating_piece[i].code)].surface,
1262 priv->floating_piece[i].pixmap_x, priv->floating_piece[i].pixmap_y);
1263 cairo_paint(priv->cr);
1265 cairo_restore(priv->cr);
1284 gboolean vertical = (priv->top_left_pixmap_x == 0);
1287 gboolean region_extends_outside_pixmap = FALSE;
1289 GdkRectangle clipbox;
1290 gdk_region_get_clipbox(region,& clipbox);
1291 if (G_UNLIKELY(clipbox.y < priv->top_left_pixmap_y))
1292 region_extends_outside_pixmap = vertical;
1293 if (G_UNLIKELY(clipbox.y + clipbox.height > priv->bottom_right_pixmap_y))
1294 region_extends_outside_pixmap = vertical;
1295 if (G_UNLIKELY(clipbox.x < priv->top_left_pixmap_x))
1296 region_extends_outside_pixmap = !vertical;
1297 if (G_UNLIKELY(clipbox.x + clipbox.width > priv->bottom_right_pixmap_x))
1298 region_extends_outside_pixmap = !vertical;
1299 if (G_UNLIKELY(region_extends_outside_pixmap))
1301 GdkRectangle pixmap_rect;
1302 pixmap_rect.x = priv->top_left_pixmap_x;
1303 pixmap_rect.y = priv->top_left_pixmap_y;
1304 pixmap_rect.width = priv->bottom_right_pixmap_x - priv->top_left_pixmap_x;
1305 pixmap_rect.height = priv->bottom_right_pixmap_y - priv->top_left_pixmap_y;
1306 GdkRegion* pixmap_region = gdk_region_rectangle(&pixmap_rect);
1307 if (CW_CHESSBOARD_EXPOSE_ALWAYS_CLEAR_BACKGROUND || priv->redraw_background)
1310 GdkRegion* outside_pixmap_region = gdk_region_copy(region);
1311 gdk_region_subtract(outside_pixmap_region, pixmap_region);
1312 GdkRectangle* outside_areas;
1313 gint n_outside_areas;
1314 gdk_region_get_rectangles(outside_pixmap_region,& outside_areas,& n_outside_areas);
1315 GdkRectangle
const* outside_rect = outside_areas;
1316 for (
int i = 0; i < n_outside_areas; ++i, ++outside_rect)
1317 gdk_window_clear_area(widget->window, outside_rect->x, outside_rect->y, outside_rect->width, outside_rect->height);
1318 #if CW_CHESSBOARD_EXPOSE_DEBUG 1320 GdkGC* debug_gc = gdk_gc_new(priv->pixmap);
1321 GdkColor debug_green = { 0, 0, 65535, 0 };
1322 gdk_colormap_alloc_color(gtk_widget_get_colormap(widget),& debug_green, FALSE, TRUE);
1323 gdk_gc_set_foreground(debug_gc,& debug_green);
1324 outside_rect = outside_areas;
1325 for (
int i = 0; i < n_outside_areas; ++i, ++outside_rect)
1326 gdk_draw_rectangle(widget->window, debug_gc, FALSE,
1327 outside_rect->x, outside_rect->y, outside_rect->width - 1, outside_rect->height - 1);
1328 g_object_unref(debug_gc);
1330 gdk_region_destroy(outside_pixmap_region);
1331 priv->redraw_background = FALSE;
1333 gdk_region_intersect(region, pixmap_region);
1334 gdk_region_destroy(pixmap_region);
1337 cairo_t* dest = gdk_cairo_create(widget->window);
1338 #if !CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER && !CW_CHESSBOARD_FLOATING_PIECE_INVALIDATE_TARGET 1339 if (priv->number_of_floating_pieces)
1342 cairo_surface_t* source = cairo_get_target(priv->cr);
1343 #if CW_CHESSBOARD_EXPOSE_DEBUG 1344 cairo_set_source_surface(dest, source, priv->top_left_pixmap_x, priv->top_left_pixmap_y);
1345 cairo_paint_with_alpha(dest, 0.35);
1347 cairo_set_source_surface(dest, source, priv->top_left_pixmap_x, priv->top_left_pixmap_y);
1348 gdk_cairo_region(dest, region);
1349 #if CW_CHESSBOARD_EXPOSE_DEBUG 1350 cairo_clip_preserve(dest);
1355 #if CW_CHESSBOARD_EXPOSE_DEBUG 1356 cairo_set_line_width(dest, 2);
1357 cairo_set_source_rgb(dest, 1, 0, 0);
1361 #if !CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 1363 if (priv->number_of_floating_pieces)
1365 #if !CW_CHESSBOARD_FLOATING_PIECE_INVALIDATE_TARGET 1366 cairo_restore(dest);
1368 for (gsize i = 0; i < priv->number_of_floating_pieces; ++i)
1369 if (priv->floating_piece[i].moved)
1371 cairo_set_source_surface(dest,
1372 priv->piece_pixmap[convert_code2piece_pixmap_index(priv->floating_piece[i].code)].surface,
1373 priv->floating_piece[i].pixmap_x + priv->top_left_pixmap_x,
1374 priv->floating_piece[i].pixmap_y + priv->top_left_pixmap_y);
1380 cairo_destroy(dest);
1382 if (priv->show_cursor || priv->floating_piece_handle != -1)
1385 Dout(dc::cwchessboardwidget,
"Calling gdk_window_get_pointer()");
1386 gdk_window_get_pointer(GTK_WIDGET(chessboard)->window, NULL, NULL, NULL);
1389 static int benchmark = 0;
1394 if (++benchmark == 100)
1405 return (gint)MAX(8.0, round(1.0 + (sside - 12) / 25.0) + sside / 3.0);
1409 cairo_t* cr, gint col, gint row, gint sside, guint hud)
1411 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_default_draw_hud_square(" << chessboard <<
", " <<
1412 cr <<
", " << col <<
", " << row <<
", " << sside <<
", " << hud <<
")");
1414 g_return_val_if_fail(hud < number_of_hud_layers, FALSE);
1415 g_return_val_if_fail(is_inside_board(col, row), FALSE);
1417 int const number_of_lines = 21;
1418 double const line_width = 0.25;
1421 if (hud == 1 || ((col + row) & 1) == 1)
1425 if (!priv->hatching_pixmap.surface)
1427 priv->hatching_pixmap.surface = cairo_surface_create_similar(cairo_get_target(priv->cr),
1428 CAIRO_CONTENT_COLOR_ALPHA, sside, sside);
1429 cairo_t* cr = cairo_create(priv->hatching_pixmap.surface);
1430 cairo_set_line_width(cr, line_width);
1431 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1432 cairo_set_source_rgb(cr, 0, 0, 0);
1433 cairo_scale(cr, (
double)sside / number_of_lines, (
double)sside / number_of_lines);
1434 for (
int h = 0; h < number_of_lines; ++h)
1436 double s = h + line_width;
1437 cairo_move_to(cr, s - 0.5 * line_width, 0.5 * line_width);
1438 cairo_line_to(cr, 0.5 * line_width, s - 0.5 * line_width);
1439 cairo_move_to(cr, s + 0.5 * line_width, number_of_lines - 0.5 * line_width);
1440 cairo_line_to(cr, number_of_lines - 0.5 * line_width, s + 0.5 * line_width);
1446 cairo_set_source_surface(cr, priv->hatching_pixmap.surface, 0, 0);
1454 g_return_if_fail(hud < number_of_hud_layers);
1458 for (gint row = 0; row < 8; ++row)
1459 for (gint col = 0; col < 8; ++col, bit <<= 1)
1461 if ((priv->hud_need_redraw[hud] & bit))
1465 cairo_translate(cr, (priv->flip_board ? 7 - col : col) * sside, (priv->flip_board ? row : 7 - row) * sside);
1466 cairo_rectangle(cr, 0, 0, sside, sside);
1468 if (CW_CHESSBOARD_GET_CLASS(chessboard)->draw_hud_square(chessboard, cr, col, row, sside, hud))
1470 priv->hud_has_content[hud] |= bit;
1471 invalidate_square(chessboard, col, row);
1478 static GdkRegion* convert_mask2region(guint64 mask, gint x, gint y, gint sside, gboolean flip_board)
1480 GdkRegion* region = gdk_region_new();
1481 guint64
row_mask = (guint64)0xff << 56;
1482 for (gint row = 7; row >= 0; --row, row_mask >>= 8)
1484 if ((mask & row_mask))
1486 guint64
col_mask = (guint64)1 << 8 * row;
1491 while (col_start != 8 && !(mask & col_mask))
1498 col_end = col_start;
1499 while (col_end != 8 && (mask & col_mask))
1505 rect.x = x + (flip_board ? 8 - col_end : col_start) * sside;
1506 rect.y = y + (flip_board ? row : 7 - row) * sside;
1507 rect.width = (col_end - col_start) * sside;
1508 rect.height = sside;
1509 gdk_region_union_with_rect(region,& rect);
1510 col_start = col_end;
1518 static void redraw_hud_layer(
CwChessboard* chessboard, guint hud)
1520 Dout(dc::cwchessboardwidget,
"Calling redraw_hud_layer(" << chessboard <<
", " << hud <<
")");
1523 gint sside = priv->sside;
1525 cairo_t* cr = cairo_create(priv->hud_layer_surface[hud]);
1526 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
1527 guint64 need_clear = priv->hud_has_content[hud] & priv->hud_need_redraw[hud];
1528 for (gint row = 0; row < 8; ++row)
1529 if ((need_clear & ((guint64)0xff << (8 * row))))
1531 guint64 bit = (guint64)1 << (8 * row);
1532 for (gint col = 0; col < 8; ++col, bit <<= 1)
1533 if ((need_clear & bit))
1535 cairo_rectangle(cr, (priv->flip_board ? 7 - col : col) * sside, (priv->flip_board ? row : 7 - row) * sside, sside, sside);
1536 invalidate_square(chessboard, col, row);
1540 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1541 priv->hud_has_content[hud]& = ~priv->hud_need_redraw[hud];
1543 if (priv->has_hud_layer[hud])
1547 priv->hud_has_content[hud] = (guint64)-1;
1548 invalidate_board(chessboard);
1550 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_hud_layer(chessboard, cr, sside, hud);
1553 GdkRegion* need_redraw_region = convert_mask2region(priv->hud_need_redraw[hud], 0, 0, priv->sside, priv->flip_board);
1554 gdk_cairo_region(cr, need_redraw_region);
1555 gdk_region_destroy(need_redraw_region);
1558 for (guint i = 0; i < priv->arrows->len; ++i)
1560 Arrow* arrow = (Arrow*)priv->arrows->pdata[i];
1561 if ((priv->hud_need_redraw[hud] & arrow->has_content[hud]))
1563 guint64 other_content = 0;
1564 for (guint h = 0; h < number_of_hud_layers; ++h)
1566 other_content |= arrow->has_content[h];
1567 gboolean has_colliding_content = (priv->hud_need_redraw[hud] & other_content) != 0;
1568 if (has_colliding_content)
1571 GdkRegion* clip_region = convert_mask2region(arrow->has_content[hud], 0, 0, priv->sside, priv->flip_board);
1572 gdk_cairo_region(cr, clip_region);
1573 gdk_region_destroy(clip_region);
1576 gdouble length = sqrt((arrow->end_col - arrow->begin_col) * (arrow->end_col - arrow->begin_col) +
1577 (arrow->end_row - arrow->begin_row) * (arrow->end_row - arrow->begin_row));
1578 gdouble begin_x = (0.5 + (priv->flip_board ? 7 - arrow->begin_col : arrow->begin_col)) * priv->sside;
1579 gdouble begin_y = (0.5 + (priv->flip_board ? arrow->begin_row : 7 - arrow->begin_row)) * priv->sside;
1581 gdouble vx = priv->sside * (arrow->end_col - arrow->begin_col) / length;
1582 gdouble vy = priv->sside * (arrow->begin_row - arrow->end_row) / length;
1583 if (priv->flip_board)
1592 cairo_move_to(cr, begin_x + 0.125 * tx, begin_y + 0.125 * ty);
1593 cairo_rel_line_to(cr, (length - 0.25) * vx, (length - 0.25) * vy);
1594 cairo_rel_line_to(cr, 0.125 * tx, 0.125 * ty);
1595 cairo_line_to(cr, begin_x + length * vx, begin_y + length * vy);
1596 cairo_line_to(cr, begin_x + (length - 0.25) * vx - 0.25 * tx,
1597 begin_y + (length - 0.25) * vy - 0.25 * ty);
1598 cairo_rel_line_to(cr, 0.125 * tx, 0.125 * ty);
1599 cairo_rel_line_to(cr, (0.25 - length) * vx, (0.25 - length) * vy);
1600 cairo_close_path(cr);
1601 cairo_set_source_rgba(cr, arrow->color.red, arrow->color.green, arrow->color.blue, 0.5);
1603 if (has_colliding_content)
1605 priv->hud_has_content[hud] |= arrow->has_content[hud];
1611 priv->hud_need_redraw[hud] = 0;
1614 static void recreate_hud_layers(
CwChessboard* chessboard)
1616 Dout(dc::cwchessboardwidget,
"Calling recreate_hud_layers(" << chessboard <<
")");
1620 for (guint hud = 0; hud < number_of_hud_layers; ++hud)
1622 if (priv->hud_layer_surface[hud])
1623 cairo_surface_destroy(priv->hud_layer_surface[hud]);
1626 priv->hud_layer_surface[hud] = cairo_surface_create_similar(cairo_get_target(priv->cr),
1627 CAIRO_CONTENT_COLOR_ALPHA, squares * priv->sside, squares * priv->sside);
1629 priv->hud_has_content[hud] = 0;
1630 priv->hud_need_redraw[hud] = (guint64)-1;
1633 invalidate_board(chessboard);
1641 return (GtkWidget*)g_object_new(CW_TYPE_CHESSBOARD, NULL);
1649 guint color_index = 0;
1650 while ((priv->allocated_colors_mask & bit))
1655 g_assert(color_index < G_N_ELEMENTS(priv->color_palet));
1656 priv->allocated_colors_mask |= bit;
1657 priv->color_palet[color_index].red = red;
1658 priv->color_palet[color_index].green = green;
1659 priv->color_palet[color_index].blue = blue;
1660 return color_index + 1;
1666 g_assert(handle > 0);
1667 guint color_index = handle - 1;
1668 g_assert(color_index < G_N_ELEMENTS(priv->color_palet));
1669 guint32 bit = 1 << color_index;
1670 g_assert((priv->allocated_colors_mask & bit) != 0);
1671 priv->allocated_colors_mask& = ~bit;
1677 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_set_marker_color(" <<
1678 chessboard <<
", " << col <<
", " << row <<
", " << (
int)mahandle <<
")");
1680 BoardIndex index = convert_colrow2index(col, row);
1682 priv->board_codes[index] = convert_mahandle2code(mahandle) | (old_code & ~mahandle_mask);
1683 invalidate_square(chessboard, col, row);
1688 return convert_code2mahandle(chessboard->priv->board_codes[convert_colrow2index(col, row)]);
1694 priv->marker_thickness = MIN(MAX(0, thickness), 0.5);
1695 priv->marker_thickness_px = MAX(1, MIN((gint)round(priv->marker_thickness * priv->sside), priv->sside / 2));
1696 invalidate_markers(chessboard);
1701 return chessboard->priv->marker_thickness;
1706 chessboard->priv->marker_below = below;
1711 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_set_background_color(" <<
1712 chessboard <<
", " << col <<
", " << row <<
", " << (
int)bghandle <<
")");
1714 BoardIndex index = convert_colrow2index(col, row);
1716 priv->board_codes[index] = convert_bghandle2code(bghandle) | (old_code & ~bghandle_mask);
1717 invalidate_square(chessboard, col, row);
1722 return convert_code2bghandle(chessboard->priv->board_codes[convert_colrow2index(col, row)]);
1729 for (
int i = 0; i < 64; ++i)
1730 if (convert_code2bghandle(board_codes[i]) != handles[i])
1737 for (
int i = 0; i < 64; ++i)
1738 handles[i] = convert_code2bghandle(board_codes[i]);
1743 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_set_square(" <<
1744 chessboard <<
", " << col <<
", " << row <<
", " << (
int)code <<
")");
1745 gint index = convert_colrow2index(col, row);
1748 if (old_code != code)
1750 board_codes[index] = (old_code & ~piece_color_mask) | (code & piece_color_mask);
1751 invalidate_square(chessboard, col, row);
1757 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_get_square(" << chessboard <<
", " << col <<
", " << row <<
")");
1758 gint index = convert_colrow2index(col, row);
1760 return board_codes[index] & piece_color_mask;
1765 if (chessboard->priv->draw_border != draw)
1767 chessboard->priv->draw_border = draw;
1768 if (GTK_WIDGET_REALIZED(chessboard))
1769 redraw_pixmap(GTK_WIDGET(chessboard));
1775 return chessboard->priv->draw_border;
1780 if (chessboard->priv->flip_board != flip)
1782 * (gboolean*)(&chessboard->
flip_board) = chessboard->priv->flip_board = flip;
1783 if (GTK_WIDGET_REALIZED(chessboard))
1785 redraw_border(chessboard);
1786 for (guint hud = 0; hud < G_N_ELEMENTS(chessboard->priv->hud_need_redraw); ++hud)
1788 chessboard->priv->hud_need_redraw[hud] = (guint64)-1;
1789 chessboard->priv->hud_has_content[hud] = (guint64)-1;
1791 invalidate_board(chessboard);
1798 return chessboard->priv->flip_board;
1804 if (priv->draw_turn_indicators != draw)
1806 priv->draw_turn_indicators = draw;
1807 if (GTK_WIDGET_REALIZED(chessboard) && priv->border_width)
1809 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_turn_indicator(chessboard, priv->active_turn_indicator, priv->draw_turn_indicators);
1810 invalidate_turn_indicators(chessboard);
1817 return chessboard->priv->draw_turn_indicators;
1823 if (priv->active_turn_indicator != white)
1825 priv->active_turn_indicator =
white;
1826 if (GTK_WIDGET_REALIZED(chessboard) && priv->border_width && priv->draw_turn_indicators)
1828 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_turn_indicator(chessboard, TRUE, white);
1829 CW_CHESSBOARD_GET_CLASS(chessboard)->draw_turn_indicator(chessboard, FALSE, !white);
1830 invalidate_turn_indicators(chessboard);
1837 return chessboard->priv->active_turn_indicator;
1842 chessboard->priv->dark_square_color_pixel = color->pixel;
1843 chessboard->priv->dark_square_color.red = color->red / 65535.0;
1844 chessboard->priv->dark_square_color.green = color->green / 65535.0;
1845 chessboard->priv->dark_square_color.blue = color->blue / 65535.0;
1846 invalidate_board(chessboard);
1851 color->pixel = chessboard->priv->dark_square_color_pixel;
1852 color->red = (guint16)round(65535.0 * chessboard->priv->dark_square_color.red);
1853 color->green = (guint16)round(65535.0 * chessboard->priv->dark_square_color.green);
1854 color->blue = (guint16)round(65535.0 * chessboard->priv->dark_square_color.blue);
1859 chessboard->priv->light_square_color_pixel = color->pixel;
1860 chessboard->priv->light_square_color.red = color->red / 65535.0;
1861 chessboard->priv->light_square_color.green = color->green / 65535.0;
1862 chessboard->priv->light_square_color.blue = color->blue / 65535.0;
1863 invalidate_board(chessboard);
1868 color->pixel = chessboard->priv->light_square_color_pixel;
1869 color->red = (guint16)round(65535.0 * chessboard->priv->light_square_color.red);
1870 color->green = (guint16)round(65535.0 * chessboard->priv->light_square_color.green);
1871 color->blue = (guint16)round(65535.0 * chessboard->priv->light_square_color.blue);
1876 chessboard->priv->board_border_color_pixel = color->pixel;
1877 chessboard->priv->board_border_color.red = color->red / 65535.0;
1878 chessboard->priv->board_border_color.green = color->green / 65535.0;
1879 chessboard->priv->board_border_color.blue = color->blue / 65535.0;
1880 if (GTK_WIDGET_REALIZED(chessboard))
1881 redraw_border(chessboard);
1886 color->pixel = chessboard->priv->board_border_color_pixel;
1887 color->red = (guint16)round(65535.0 * chessboard->priv->board_border_color.red);
1888 color->green = (guint16)round(65535.0 * chessboard->priv->board_border_color.green);
1889 color->blue = (guint16)round(65535.0 * chessboard->priv->board_border_color.blue);
1894 chessboard->priv->white_piece_fill_color_pixel = color->pixel;
1895 chessboard->priv->white_piece_fill_color.red = color->red / 65535.0;
1896 chessboard->priv->white_piece_fill_color.green = color->green / 65535.0;
1897 chessboard->priv->white_piece_fill_color.blue = color->blue / 65535.0;
1898 if (GTK_WIDGET_REALIZED(chessboard))
1899 redraw_pieces(chessboard);
1904 color->pixel = chessboard->priv->white_piece_fill_color_pixel;
1905 color->red = (guint16)round(65535.0 * chessboard->priv->white_piece_fill_color.red);
1906 color->green = (guint16)round(65535.0 * chessboard->priv->white_piece_fill_color.green);
1907 color->blue = (guint16)round(65535.0 * chessboard->priv->white_piece_fill_color.blue);
1912 chessboard->priv->white_piece_line_color_pixel = color->pixel;
1913 chessboard->priv->white_piece_line_color.red = color->red / 65535.0;
1914 chessboard->priv->white_piece_line_color.green = color->green / 65535.0;
1915 chessboard->priv->white_piece_line_color.blue = color->blue / 65535.0;
1916 if (GTK_WIDGET_REALIZED(chessboard))
1917 redraw_pieces(chessboard);
1922 color->pixel = chessboard->priv->white_piece_line_color_pixel;
1923 color->red = (guint16)round(65535.0 * chessboard->priv->white_piece_line_color.red);
1924 color->green = (guint16)round(65535.0 * chessboard->priv->white_piece_line_color.green);
1925 color->blue = (guint16)round(65535.0 * chessboard->priv->white_piece_line_color.blue);
1930 chessboard->priv->black_piece_fill_color_pixel = color->pixel;
1931 chessboard->priv->black_piece_fill_color.red = color->red / 65535.0;
1932 chessboard->priv->black_piece_fill_color.green = color->green / 65535.0;
1933 chessboard->priv->black_piece_fill_color.blue = color->blue / 65535.0;
1934 if (GTK_WIDGET_REALIZED(chessboard))
1935 redraw_pieces(chessboard);
1940 color->pixel = chessboard->priv->black_piece_fill_color_pixel;
1941 color->red = (guint16)round(65535.0 * chessboard->priv->black_piece_fill_color.red);
1942 color->green = (guint16)round(65535.0 * chessboard->priv->black_piece_fill_color.green);
1943 color->blue = (guint16)round(65535.0 * chessboard->priv->black_piece_fill_color.blue);
1948 chessboard->priv->black_piece_line_color_pixel = color->pixel;
1949 chessboard->priv->black_piece_line_color.red = color->red / 65535.0;
1950 chessboard->priv->black_piece_line_color.green = color->green / 65535.0;
1951 chessboard->priv->black_piece_line_color.blue = color->blue / 65535.0;
1952 if (GTK_WIDGET_REALIZED(chessboard))
1953 redraw_pieces(chessboard);
1958 color->pixel = chessboard->priv->black_piece_line_color_pixel;
1959 color->red = (guint16)round(65535.0 * chessboard->priv->black_piece_line_color.red);
1960 color->green = (guint16)round(65535.0 * chessboard->priv->black_piece_line_color.green);
1961 color->blue = (guint16)round(65535.0 * chessboard->priv->black_piece_line_color.blue);
1966 chessboard->priv->cursor_color_pixel = color->pixel;
1967 chessboard->priv->cursor_color.red = color->red / 65535.0;
1968 chessboard->priv->cursor_color.green = color->green / 65535.0;
1969 chessboard->priv->cursor_color.blue = color->blue / 65535.0;
1970 invalidate_cursor(chessboard);
1975 color->pixel = chessboard->priv->cursor_color_pixel;
1976 color->red = (guint16)round(65535.0 * chessboard->priv->cursor_color.red);
1977 color->green = (guint16)round(65535.0 * chessboard->priv->cursor_color.green);
1978 color->blue = (guint16)round(65535.0 * chessboard->priv->cursor_color.blue);
1984 priv->cursor_thickness = MIN(MAX(0, thickness), 0.5);
1985 priv->cursor_thickness_px = MAX(1, MIN((gint)round(priv->cursor_thickness * priv->sside), priv->sside / 2));
1986 invalidate_cursor(chessboard);
1991 return chessboard->priv->cursor_thickness;
1996 GtkWidget* widget = GTK_WIDGET(chessboard);
1998 if (priv->show_cursor)
2000 priv->show_cursor = TRUE;
2003 Dout(dc::cwchessboardwidget,
"Calling gdk_window_get_pointer()");
2004 gdk_window_get_pointer(widget->window,& x,& y, NULL);
2005 update_cursor_position(chessboard, x, y, TRUE);
2011 invalidate_cursor(chessboard);
2012 priv->show_cursor = FALSE;
2017 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_move_floating_piece(" <<
2018 chessboard <<
", " << (
int)handle <<
", " << x <<
", " << y <<
")");
2020 GtkWidget* widget = GTK_WIDGET(chessboard);
2024 g_assert(handle >= 0 && (gsize)handle < G_N_ELEMENTS(priv->floating_piece));
2025 g_assert(!is_empty_square(priv->floating_piece[handle].code));
2031 rect.width = priv->sside;
2032 rect.height = priv->sside;
2033 rect.x = priv->floating_piece[handle].pixmap_x + priv->top_left_pixmap_x;
2034 rect.y = priv->floating_piece[handle].pixmap_y + priv->top_left_pixmap_y;
2035 gdk_window_invalidate_rect(widget->window,& rect, FALSE);
2036 #if CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 2039 if (is_inside_board(col, row))
2041 BoardIndex index = convert_colrow2index(col, row);
2042 guint64 redraw_mask = 1;
2043 priv->need_redraw |= (redraw_mask << index);
2045 col += priv->flip_board ? -1 : 1;
2046 if (is_inside_board(col, row))
2048 BoardIndex index = convert_colrow2index(col, row);
2049 guint64 redraw_mask = 1;
2050 priv->need_redraw |= (redraw_mask << index);
2052 row += priv->flip_board ? 1 : -1;
2053 if (is_inside_board(col, row))
2055 BoardIndex index = convert_colrow2index(col, row);
2056 guint64 redraw_mask = 1;
2057 priv->need_redraw |= (redraw_mask << index);
2059 col += priv->flip_board ? 1 : -1;
2060 if (is_inside_board(col, row))
2062 BoardIndex index = convert_colrow2index(col, row);
2063 guint64 redraw_mask = 1;
2064 priv->need_redraw |= (redraw_mask << index);
2067 gboolean outside_window =
2068 rect.x + rect.width < 0 ||
2069 rect.x > widget->allocation.x ||
2070 rect.y + rect.height < 0 ||
2071 rect.y > widget->allocation.y;
2073 priv->redraw_background = priv->redraw_background ||
2074 rect.x < priv->top_left_pixmap_x ||
2075 rect.x + rect.width > priv->bottom_right_pixmap_x ||
2076 rect.y < priv->top_left_pixmap_y ||
2077 rect.y + rect.height > priv->bottom_right_pixmap_y;
2078 rect.x = (gint)trunc(x - 0.5 * priv->sside);
2079 rect.y = (gint)trunc(y - 0.5 * priv->sside);
2080 #if CW_CHESSBOARD_FLOATING_PIECE_INVALIDATE_TARGET || CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 2081 gdk_window_invalidate_rect(widget->window,& rect, FALSE);
2082 outside_window = outside_window&&
2083 (rect.x + rect.width < 0 ||
2084 rect.x > widget->allocation.x ||
2085 rect.y + rect.height < 0 ||
2086 rect.y > widget->allocation.y);
2088 if (outside_window && priv->floating_piece[handle].pointer_device)
2090 Dout(dc::cwchessboardwidget,
"Calling gdk_window_get_pointer()");
2091 gdk_window_get_pointer(widget->window, NULL, NULL, NULL);
2093 priv->floating_piece[handle].pixmap_x = rect.x - priv->top_left_pixmap_x;
2094 priv->floating_piece[handle].pixmap_y = rect.y - priv->top_left_pixmap_y;
2095 priv->floating_piece[handle].moved = TRUE;
2099 gdouble x, gdouble y, gboolean pointer_device)
2101 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_add_floating_piece(" << chessboard <<
", code:" << code <<
2102 ", x:" << x <<
", y:" << y <<
", " << pointer_device <<
")");
2107 g_assert(priv->number_of_floating_pieces < G_N_ELEMENTS(priv->floating_piece));
2109 priv->number_of_floating_pieces++;
2111 while (priv->floating_piece[handle].code !=
empty_square)
2114 rect.x = (gint)trunc(x - 0.5 * priv->sside);
2115 rect.y = (gint)trunc(y - 0.5 * priv->sside);
2116 priv->floating_piece[handle].code = code & piece_color_mask;
2117 priv->floating_piece[handle].pixmap_x = rect.x - priv->top_left_pixmap_x;
2118 priv->floating_piece[handle].pixmap_y = rect.y - priv->top_left_pixmap_y;
2119 priv->floating_piece[handle].moved = TRUE;
2120 if (priv->floating_piece_handle != -1)
2121 pointer_device = FALSE;
2122 priv->floating_piece[handle].pointer_device = pointer_device;
2124 priv->floating_piece_handle = handle;
2125 #if CW_CHESSBOARD_FLOATING_PIECE_INVALIDATE_TARGET || CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 2127 rect.width = priv->sside;
2128 rect.height = priv->sside;
2129 gdk_window_invalidate_rect(GTK_WIDGET(chessboard)->window,& rect, FALSE);
2132 rect.width = priv->sside;
2133 rect.height = priv->sside;
2134 gdk_window_invalidate_rect(GTK_WIDGET(chessboard)->window,& rect, FALSE);
2137 Dout(dc::cwchessboardwidget,
"number_of_floating_pieces = " << priv->number_of_floating_pieces);
2138 Dout(dc::cwchessboardwidget,
"Allocated handle " << handle);
2145 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_remove_floating_piece(" << chessboard <<
", handle:" << handle <<
")");
2150 g_assert(handle >= 0 && (gsize)handle < G_N_ELEMENTS(priv->floating_piece));
2151 g_assert(!is_empty_square(priv->floating_piece[handle].code));
2154 rect.width = priv->sside;
2155 rect.height = priv->sside;
2156 rect.x = priv->floating_piece[handle].pixmap_x + priv->top_left_pixmap_x;
2157 rect.y = priv->floating_piece[handle].pixmap_y + priv->top_left_pixmap_y;
2158 gdk_window_invalidate_rect(GTK_WIDGET(chessboard)->window,& rect, FALSE);
2159 #if CW_CHESSBOARD_FLOATING_PIECE_DOUBLE_BUFFER 2162 if (is_inside_board(col, row))
2164 BoardIndex index = convert_colrow2index(col, row);
2165 guint64 redraw_mask = 1;
2166 priv->need_redraw |= (redraw_mask << index);
2168 col += priv->flip_board ? -1 : 1;
2169 if (is_inside_board(col, row))
2171 BoardIndex index = convert_colrow2index(col, row);
2172 guint64 redraw_mask = 1;
2173 priv->need_redraw |= (redraw_mask << index);
2175 row += priv->flip_board ? 1 : -1;
2176 if (is_inside_board(col, row))
2178 BoardIndex index = convert_colrow2index(col, row);
2179 guint64 redraw_mask = 1;
2180 priv->need_redraw |= (redraw_mask << index);
2182 col += priv->flip_board ? 1 : -1;
2183 if (is_inside_board(col, row))
2185 BoardIndex index = convert_colrow2index(col, row);
2186 guint64 redraw_mask = 1;
2187 priv->need_redraw |= (redraw_mask << index);
2191 priv->redraw_background = priv->redraw_background ||
2192 rect.x < priv->top_left_pixmap_x ||
2193 rect.x + rect.width > priv->bottom_right_pixmap_x ||
2194 rect.y < priv->top_left_pixmap_y ||
2195 rect.y + rect.height > priv->bottom_right_pixmap_y;
2196 if (priv->floating_piece[handle].pointer_device)
2197 priv->floating_piece_handle = -1;
2198 priv->number_of_floating_pieces--;
2200 Dout(dc::cwchessboardwidget,
"number_of_floating_pieces = " << priv->number_of_floating_pieces);
2205 g_assert(handle >= 0 && (gsize)handle < G_N_ELEMENTS(chessboard->priv->floating_piece));
2206 return chessboard->priv->floating_piece[handle].code;
2211 g_return_if_fail(hud < number_of_hud_layers);
2212 chessboard->priv->has_hud_layer[hud] = TRUE;
2213 chessboard->priv->hud_need_redraw[hud] = (guint64)-1;
2218 g_return_if_fail(hud < number_of_hud_layers);
2219 chessboard->priv->has_hud_layer[hud] = FALSE;
2220 chessboard->priv->hud_need_redraw[hud] = (guint64)-1;
2223 static guint64 invalidate_arrow(
CwChessboard* chessboard, gint col1, gint row1, gint col2, gint row2)
2225 Dout(dc::cwchessboardwidget|continued_cf,
"Calling invalidate_arrow(" << chessboard <<
", " <<
2226 col1 <<
", " << row1 <<
", " << col2 <<
", " << row2 <<
") = ");
2236 guint64 bit = (guint64)1 << convert_colrow2index(col1, row1);
2237 for (gint row = row1; row <= row2; ++row, bit <<= 8)
2240 invalidate_square(chessboard, col1, row);
2242 Dout(dc::finish, std::hex << result);
2245 else if (row1 == row2)
2253 guint64 bit = (guint64)1 << convert_colrow2index(col1, row1);
2254 for (gint col = col1; col <= col2; ++col, bit <<= 1)
2257 invalidate_square(chessboard, col, row1);
2259 Dout(dc::finish, std::hex << result);
2266 tmp = col1; col1 = col2; col2 = tmp;
2267 tmp = row1; row1 = row2; row2 = tmp;
2269 double const arrow_width = 0.125;
2270 double delta = arrow_width*
2271 sqrt((row2 - row1) * (row2 - row1) + (col2 - col1) * (col2 - col1)) / (row2 - row1);
2272 gint col_start = col1;
2281 for (
double r = row1 + 0.5; r < row2; r += 1.0)
2283 double c = col1 + (r - row1) * (col2 - col1) / (row2 - row1);
2284 gint col_end = (gint)round(c + delta);
2285 guint64 mask1 = (sign << convert_colrow2index(col_start, row)) - 1;
2286 guint64 mask2 = ((3 - sign) << convert_colrow2index(col_end, row)) - 1;
2287 result |= mask1 ^ mask2;
2288 col_start = (gint)round(c - delta);
2291 guint64 mask1 = (sign << convert_colrow2index(col_start, row)) - 1;
2292 guint64 mask2 = ((3 - sign) << convert_colrow2index(col2, row)) - 1;
2293 result |= mask1 ^ mask2;
2294 Dout(dc::finish, std::hex << result);
2296 for (gint row = 0; row < squares; ++row)
2297 for (gint col = 0; col < squares; ++col, bit <<= 1)
2299 invalidate_square(chessboard, col, row);
2304 gint begin_col, gint begin_row, gint end_col, gint end_row, GdkColor
const* color)
2306 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_add_arrow(" << chessboard <<
", " <<
2307 begin_col <<
", " << begin_row <<
", " << end_col <<
", " << end_row <<
", " << color <<
")");
2309 g_return_val_if_fail(begin_col != end_col || begin_row != end_row, NULL);
2310 g_return_val_if_fail(is_inside_board(begin_col, begin_row) && is_inside_board(end_col, end_row), NULL);
2312 Arrow* arrow = (Arrow*)g_malloc(
sizeof(Arrow));
2313 g_ptr_array_add(chessboard->priv->arrows, arrow);
2314 arrow->begin_col = begin_col;
2315 arrow->begin_row = begin_row;
2316 arrow->end_col = end_col;
2317 arrow->end_row = end_row;
2318 arrow->color.red = color->red / 65535.0;
2319 arrow->color.green = color->green / 65535.0;
2320 arrow->color.blue = color->blue / 65535.0;
2321 guint64 content = invalidate_arrow(chessboard, begin_col, begin_row, end_col, end_row);
2322 guint64 start_square = (guint64)1 << convert_colrow2index(begin_col, begin_row);
2323 chessboard->priv->hud_need_redraw[0] |= (arrow->has_content[0] = start_square);
2324 chessboard->priv->hud_need_redraw[1] |= (arrow->has_content[1] = content ^ start_square);
2330 Dout(dc::cwchessboardwidget,
"Calling cw_chessboard_remove_arrow(" << chessboard <<
", " << ptr <<
")");
2331 if (g_ptr_array_remove_fast(chessboard->priv->arrows, ptr))
2333 Arrow* arrow = (Arrow*)ptr;
2334 chessboard->priv->hud_need_redraw[0] |= arrow->has_content[0];
2335 chessboard->priv->hud_need_redraw[1] |= arrow->has_content[1];
2343 static double const black_line_width = CONST(black_line_width, 0.026);
2344 static double const white_line_width = CONST(white_line_width, 1.5 * black_line_width);
2346 static double snap_bottom(
double y,
double translate,
double scale,
double line_width)
2350 return (round((y + 0.5 * line_width) * scale - translate) + translate) / scale - 0.5 * line_width;
2353 static double snap_top(
double y,
double translate,
double scale,
double line_width)
2357 return (round((y - 0.5 * line_width) * scale - translate) + translate) / scale + 0.5 * line_width;
2360 static double snap_line_width(
double line_width,
double scale)
2362 if (line_width * scale < 1.0)
2364 return trunc(line_width * scale + 0.3) / scale;
2371 cairo_set_source_rgb(cr, priv->white_piece_fill_color.red,
2372 priv->white_piece_fill_color.green,
2373 priv->white_piece_fill_color.blue);
2375 cairo_set_source_rgb(cr, priv->black_piece_fill_color.red,
2376 priv->black_piece_fill_color.green,
2377 priv->black_piece_fill_color.blue);
2384 cairo_set_source_rgb(cr, priv->white_piece_line_color.red,
2385 priv->white_piece_line_color.green,
2386 priv->white_piece_line_color.blue);
2388 cairo_set_source_rgb(cr, priv->black_piece_line_color.red,
2389 priv->black_piece_line_color.green,
2390 priv->black_piece_line_color.blue);
2396 static double const base_outside_diameter_cm = CONST(base_outside_diameter_cm, 3.265);
2397 static double const width_pawn_cm = CONST(width_pawn_cm, 5.31);
2398 static double const base_radius = CONST(base_radius, 0.5 * (base_outside_diameter_cm / width_pawn_cm - black_line_width));
2399 static double const mid_outside_diameter_cm = CONST(mid_outside_diameter_cm, 1.98);
2400 static double const mid_radius = CONST(mid_radius, 0.5 * (mid_outside_diameter_cm / width_pawn_cm - black_line_width));
2401 static double const head_outside_diameter_cm = CONST(head_outside_diameter_cm, 1.12);
2402 static double const head_radius = CONST(head_radius, 0.5 * (head_outside_diameter_cm / width_pawn_cm - black_line_width));
2403 static double const height_pawn_cm = CONST(height_pawn_cm, 5.43);
2404 static double const bottom_pawn_cm = CONST(bottom_pawn_cm, 0.58);
2405 static double const foot_height = CONST(foot_height, 0.0387);
2406 static double const base_y = CONST(base_y, 0.5 - bottom_pawn_cm / height_pawn_cm - 0.5 * black_line_width);
2407 static double const base_scale = CONST(base_scale, 0.931);
2408 static double const mid_y = CONST(mid_y, -0.0545);
2409 static double const top_offset_cm = CONST(top_offset_cm, 0.62);
2410 static double const head_y = CONST(head_y, -0.5 + top_offset_cm / height_pawn_cm + 0.5 * black_line_width + head_radius);
2412 static double const base_angle = CONST(base_angle, 1.148);
2413 static double const mid_angle1 = CONST(mid_angle1, 0.992);
2414 static double const inner_neck_width_cm = CONST(inner_neck_width_cm, 0.41);
2415 static double const neck_right = CONST(neck_right, 0.5 * (inner_neck_width_cm / width_pawn_cm + black_line_width));
2416 static double const head_angle = CONST(head_angle, asin(neck_right / head_radius));
2417 static double const mid_scale = CONST(mid_scale, (mid_y - (head_y + head_radius * cos(head_angle)) -
2418 0.1 * black_line_width) / sqrt(mid_radius * mid_radius - neck_right * neck_right));
2419 static double const mid_angle2 = CONST(mid_angle2, asin(head_radius * sin(head_angle) / mid_radius));
2421 double const base_y_sn = snap_bottom(base_y, y, scale, black_line_width);
2426 cairo_translate(cr, x, y);
2427 cairo_scale(cr, scale, scale);
2428 cairo_set_line_width(cr, black_line_width);
2431 cairo_move_to(cr, -base_radius, base_y_sn);
2433 cairo_translate(cr, 0.0, base_y_sn - foot_height);
2434 cairo_scale(cr, 1.0, base_scale);
2435 cairo_arc(cr, 0.0, 0.0, base_radius, -M_PI, -M_PI + base_angle);
2440 cairo_translate(cr, 0.0, mid_y);
2441 cairo_scale(cr, 1.0, mid_scale);
2442 cairo_arc(cr, 0.0, 0.0, mid_radius, -M_PI - mid_angle1, -0.5 * M_PI - mid_angle2);
2446 cairo_arc(cr, 0.0, head_y, head_radius, -1.5 * M_PI + head_angle, 0.5 * M_PI - head_angle);
2450 cairo_translate(cr, 0.0, mid_y);
2451 cairo_scale(cr, 1.0, mid_scale);
2452 cairo_arc(cr, 0.0, 0.0, mid_radius, -0.5 * M_PI + mid_angle2, mid_angle1);
2457 cairo_translate(cr, 0.0, base_y_sn - foot_height);
2458 cairo_scale(cr, 1.0, base_scale);
2459 cairo_arc(cr, 0.0, 0.0, base_radius, -base_angle, 0.0);
2461 cairo_line_to(cr, base_radius, base_y_sn);
2464 cairo_close_path(cr);
2466 set_fill_color(cr, priv, white);
2467 cairo_fill_preserve(cr);
2469 set_line_color(cr, priv, white);
2478 static double const blob_left_cm = CONST(blob_left_cm, 1.22);
2479 static double const band_edge_left_cm = CONST(band_edge_left_cm, 2.55);
2480 static double const band_left_cm = CONST(band_left_cm, 2.67);
2481 static double const inside_left_cm = CONST(inside_left_cm, 3.06);
2482 static double const center_blob_left_cm = CONST(center_blob_left_cm, 4.525);
2483 static double const cross_left_cm = CONST(cross_left_cm, 4.71);
2484 static double const width_king_cm = CONST(width_king_cm, 10.67);
2485 static double const bottom_king_cm = CONST(bottom_king_cm, 1.155);
2486 static double const band_line_top_cm = CONST(band_line_top_cm, 2.95);
2487 static double const band_top_king_cm = CONST(band_top_king_cm, 4.04);
2488 static double const center_y_cm = CONST(center_y_cm, 5.02);
2489 static double const blob_top_cm = CONST(blob_top_cm, 7.4);
2490 static double const center_blob_top_cm = CONST(center_blob_top_cm, 8.18);
2491 static double const cross_y_king_cm = CONST(cross_y_king_cm, 9.17);
2492 static double const cross_top_cm = CONST(cross_top_cm, 9.86);
2493 static double const height_king_cm = CONST(height_king_cm, 10.86);
2495 static double const mid_x_king_cm = CONST(mid_x_king_cm, width_king_cm / 2);
2496 static double const mid_y_king_cm = CONST(mid_y_king_cm, height_king_cm / 2);
2499 static double const blob_left = CONST(blob_left, (blob_left_cm - mid_x_king_cm) / width_king_cm);
2500 static double const band_edge_left = CONST(band_edge_left, (band_edge_left_cm - mid_x_king_cm) / width_king_cm);
2501 static double const band_left = CONST(band_left, (band_left_cm - mid_x_king_cm) / width_king_cm);
2502 static double const inside_left = CONST(inside_left, (inside_left_cm - mid_x_king_cm) / width_king_cm);
2503 static double const center_blob_left = CONST(center_blob_left, (center_blob_left_cm - mid_x_king_cm) / width_king_cm);
2504 static double const cross_left = CONST(cross_left, (cross_left_cm - mid_x_king_cm) / width_king_cm);
2505 static double const bottom_king = CONST(bottom_king, (mid_y_king_cm - bottom_king_cm) / height_king_cm);
2506 static double const band_line_top = CONST(band_line_top, (mid_y_king_cm - band_line_top_cm) / height_king_cm);
2507 static double const band_top_king = CONST(band_top_king, (mid_y_king_cm - band_top_king_cm) / height_king_cm);
2508 static double const center_y = CONST(center_y, (mid_y_king_cm - center_y_cm) / height_king_cm);
2509 static double const blob_top = CONST(blob_top, (mid_y_king_cm - blob_top_cm) / height_king_cm);
2510 static double const center_blob_top = CONST(center_blob_top, (mid_y_king_cm - center_blob_top_cm) / height_king_cm);
2511 static double const cross_y_king = CONST(cross_y_king, (mid_y_king_cm - cross_y_king_cm) / height_king_cm);
2512 static double const cross_top = CONST(cross_top, (mid_y_king_cm - cross_top_cm) / height_king_cm);
2515 static double const inside_radius_king = CONST(inside_radius_king, -inside_left);
2516 static double const inside_scale_king = CONST(inside_scale_king, 0.180132);
2517 static double const band_top_radius = CONST(band_top_radius, -band_edge_left);
2518 static double const band_top_scale = CONST(band_top_scale, inside_scale_king);
2519 static double const band_top_y = CONST(band_top_y, band_top_king + band_top_radius * band_top_scale);
2520 static double const cos_alpha = CONST(cos_alpha, band_left / band_edge_left);
2521 static double const alpha = CONST(alpha, acos(cos_alpha));
2522 static double const band_bottom_scale = CONST(band_bottom_scale, inside_scale_king);
2523 static double const band_bottom_radius = CONST(band_bottom_radius, band_top_radius);
2524 static double const band_bottom_y = CONST(band_bottom_y, bottom_king - band_bottom_radius * band_bottom_scale);
2525 static double const dx = CONST(dx, band_top_radius * (1.0 - cos_alpha));
2526 static double const band_line_scale = CONST(band_line_scale, band_top_scale);
2527 static double const band_line_radius = CONST(band_line_radius, band_top_radius - dx);
2528 static double const band_line_y = CONST(band_line_y, band_line_top + band_line_radius * band_line_scale);
2529 static double const blob_radius = CONST(blob_radius, 0.7071067 * (blob_left + band_top_y - band_left - blob_top));
2530 static double const blob_x = CONST(blob_x, blob_left + blob_radius);
2531 static double const blob_y = CONST(blob_y, blob_top + blob_radius);
2532 static double const center_blob_radius = CONST(center_blob_radius, -center_blob_left);
2533 static double const center_blob_y = CONST(center_blob_y, center_blob_top + center_blob_radius);
2535 static double const adjusted_center_blob_radius = CONST(adjusted_center_blob_radius, center_blob_radius + 0.01);
2536 static double const beta_king = CONST(beta_king, asin(adjusted_center_blob_radius / (center_y - center_blob_y)));
2537 static double const center2_y = CONST(center2_y, blob_y - blob_x - 1.4142136 * blob_radius);
2542 cairo_translate(cr, x, y);
2543 cairo_scale(cr, scale, scale);
2544 cairo_set_line_width(cr, black_line_width);
2547 cairo_move_to(cr, band_left, band_top_y);
2548 cairo_arc(cr, blob_x, blob_y, blob_radius, 0.75 * M_PI, 1.75 * M_PI);
2549 cairo_line_to(cr, 0.0, center2_y);
2552 cairo_arc(cr, -blob_x, blob_y, blob_radius, -0.75 * M_PI, 0.25 * M_PI);
2553 cairo_line_to(cr, -band_left, band_top_y);
2555 set_fill_color(cr, priv, white);
2556 cairo_fill_preserve(cr);
2559 cairo_move_to(cr, 0.0, band_top_y);
2560 cairo_line_to(cr, 0.0, center_y);
2563 set_line_color(cr, priv, white);
2567 cairo_move_to(cr, 0.0, center_y);
2568 cairo_arc(cr, 0.0, center_blob_y, adjusted_center_blob_radius, M_PI - beta_king, beta_king);
2569 cairo_close_path(cr);
2572 set_fill_color(cr, priv, white);
2573 cairo_fill_preserve(cr);
2575 set_line_color(cr, priv, white);
2579 cairo_move_to(cr, 0.0, center_blob_y - adjusted_center_blob_radius);
2580 cairo_line_to(cr, 0.0, cross_top);
2581 cairo_move_to(cr, cross_left, cross_y_king);
2582 cairo_line_to(cr, -cross_left, cross_y_king);
2587 cairo_translate(cr, 0.0, band_top_y);
2588 cairo_scale(cr, 1.0, band_top_scale);
2589 cairo_arc(cr, 0.0, 0.0, band_top_radius, M_PI - alpha, 2 * M_PI + alpha);
2593 cairo_line_to(cr, -band_left, band_line_y);
2597 cairo_translate(cr, 0.0, band_bottom_y);
2598 cairo_scale(cr, 1.0, band_bottom_scale);
2599 cairo_arc(cr, 0.0, 0.0, band_bottom_radius, 0.0, M_PI);
2603 cairo_line_to(cr, band_left, band_line_y);
2606 cairo_close_path(cr);
2608 cairo_path_t* path = cairo_copy_path(cr);
2611 set_fill_color(cr, priv, white);
2616 cairo_translate(cr, 0.0, band_line_y);
2617 cairo_scale(cr, 1.0, band_line_scale);
2618 cairo_arc(cr, 0.0, 0.0, band_line_radius, -M_PI, 0.0);
2621 cairo_new_sub_path(cr);
2625 cairo_translate(cr, 0.0, band_bottom_y + band_bottom_radius * band_bottom_scale - inside_radius_king * inside_scale_king);
2626 cairo_scale(cr, 1.0, inside_scale_king);
2628 cairo_arc(cr, 0.0, 0.0, inside_radius_king, -M_PI, M_PI);
2630 cairo_arc(cr, 0.0, 0.0, inside_radius_king, -M_PI - alpha, alpha);
2633 set_line_color(cr, priv, white);
2638 cairo_set_line_width(cr, white_line_width);
2640 cairo_set_line_width(cr, black_line_width);
2643 cairo_append_path(cr, path);
2645 set_fill_color(cr, priv, white);
2648 cairo_path_destroy(path);
2654 static double const av_line_width = CONST(av_line_width, 0.5 * (black_line_width + white_line_width));
2655 static double const da = CONST(da, av_line_width / band_top_radius);
2656 static double const dy = CONST(dy, av_line_width * tan(0.5 * beta_king));
2659 cairo_translate(cr, 0.0, band_top_y);
2660 cairo_scale(cr, 1.0, band_top_scale);
2661 cairo_arc_negative(cr, 0.0, 0.0, band_top_radius, -0.5 * M_PI - da, M_PI + alpha + da);
2664 cairo_arc(cr, blob_x, blob_y, blob_radius - av_line_width, 0.75 * M_PI, 1.75 * M_PI);
2666 static double const center2b_y = CONST(center2b_y, center2_y + av_line_width * 1.4142136);
2667 static double const sin_beta = CONST(sin_beta, adjusted_center_blob_radius / (center_y - center_blob_y));
2668 static double const x_king = CONST(x_king, sin_beta * (center_y + av_line_width / sin_beta - center2b_y) / sin(0.25 * M_PI - beta_king));
2669 static double const y_king = CONST(y_king, center2b_y - x_king);
2671 cairo_line_to(cr, -x_king, y_king);
2672 cairo_line_to(cr, -av_line_width, center_y + dy);
2674 cairo_close_path(cr);
2676 cairo_new_sub_path(cr);
2679 cairo_translate(cr, 0.0, band_top_y);
2680 cairo_scale(cr, 1.0, band_top_scale);
2681 cairo_arc_negative(cr, 0.0, 0.0, band_top_radius, -alpha - da, -0.5 * M_PI + da);
2684 cairo_line_to(cr, av_line_width, center_y + dy);
2685 cairo_line_to(cr, x_king, y_king);
2687 cairo_arc(cr, -blob_x, blob_y, blob_radius - av_line_width, -0.75 * M_PI, 0.25 * M_PI);
2689 cairo_close_path(cr);
2691 cairo_new_sub_path(cr);
2693 cairo_move_to(cr, 0.0, center_y - av_line_width / sin_beta);
2694 cairo_arc(cr, 0.0, center_blob_y, adjusted_center_blob_radius - av_line_width, M_PI - beta_king, beta_king);
2696 cairo_close_path(cr);
2698 set_line_color(cr, priv, white);
2699 cairo_set_line_width(cr, white_line_width);
2709 static double const width_queen_cm = CONST(width_queen_cm, 5.34);
2710 static double const inside_width_cm = CONST(inside_width_cm, 2.97);
2711 static double const band1_width_cm = CONST(band1_width_cm, 2.59);
2712 static double const crown_bottom_width_cm = CONST(crown_bottom_width_cm, 3.31);
2713 static double const height_queen_cm = CONST(height_queen_cm, 5.39);
2714 static double const bottom_queen_cm = CONST(bottom_queen_cm, 0.5);
2715 static double const inside_height_cm = CONST(inside_height_cm, 0.54);
2716 static double const band1_height_cm = CONST(band1_height_cm, 0.47);
2717 static double const band2_height_cm = CONST(band2_height_cm, 0.43);
2718 static double const tooth_outside_cm = CONST(tooth_outside_cm, 1.83);
2719 static double const tooth_inside_cm = CONST(tooth_inside_cm, 2.20);
2720 static double const tooth_inside2_cm = CONST(tooth_inside2_cm, 2.36);
2721 static double const ball_outside_diameter_cm = CONST(ball_outside_diameter_cm, 0.6);
2722 static double const ball_top1_cm = CONST(ball_top1_cm, 4.31);
2723 static double const ball_right1_cm = CONST(ball_right1_cm, 0.90);
2724 static double const ball_top2_cm = CONST(ball_top2_cm, 4.80);
2725 static double const ball_right2_cm = CONST(ball_right2_cm, 1.88);
2726 static double const tooth3_x_cm = CONST(tooth3_x_cm, 2.25);
2728 static double const mid_x_queen_cm = CONST(mid_x_queen_cm, width_queen_cm / 2);
2729 static double const mid_y_queen_cm = CONST(mid_y_queen_cm, height_queen_cm / 2);
2732 static double const inside_width = CONST(inside_width, inside_width_cm / width_queen_cm);
2733 static double const band1_width = CONST(band1_width, band1_width_cm / width_queen_cm);
2734 static double const crown_bottom_width = CONST(crown_bottom_width, crown_bottom_width_cm / width_queen_cm);
2735 static double const bottom_queen = CONST(bottom_queen, (mid_y_queen_cm - bottom_queen_cm) / height_queen_cm);
2736 static double const inside_height = CONST(inside_height, inside_height_cm / height_queen_cm);
2737 static double const band1_height = CONST(band1_height, band1_height_cm / height_queen_cm);
2738 static double const band2_height = CONST(band2_height, band2_height_cm / height_queen_cm);
2739 static double const tooth_outside = CONST(tooth_outside, (mid_y_queen_cm - tooth_outside_cm) / height_queen_cm);
2740 static double const tooth_inside = CONST(tooth_inside, (mid_y_queen_cm - tooth_inside_cm) / height_queen_cm);
2741 static double const tooth_inside2 = CONST(tooth_inside2, (mid_y_queen_cm - tooth_inside2_cm) / height_queen_cm);
2742 static double const ball_outside_diameter = CONST(ball_outside_diameter, ball_outside_diameter_cm / height_queen_cm);
2743 static double const ball_top1 = CONST(ball_top1, (mid_y_queen_cm - ball_top1_cm) / height_queen_cm);
2744 static double const ball_right1 = CONST(ball_right1, (ball_right1_cm - mid_x_queen_cm) / width_queen_cm);
2745 static double const ball_top2 = CONST(ball_top2, (mid_y_queen_cm - ball_top2_cm) / height_queen_cm);
2746 static double const ball_right2 = CONST(ball_right2, (ball_right2_cm - mid_x_queen_cm) / width_queen_cm);
2747 static double const tooth3_x = CONST(tooth3_x, (tooth3_x_cm - mid_x_queen_cm) / width_queen_cm);
2750 static double const inside_radius_queen = CONST(inside_radius_queen, inside_width / 2);
2751 static double const inside_scale_queen = CONST(inside_scale_queen, inside_height / inside_width);
2752 static double const inside_y_queen = CONST(inside_y_queen, bottom_queen - inside_radius_queen * inside_scale_queen);
2753 static double const band1_radius = CONST(band1_radius, band1_width / 2);
2754 static double const band1_scale = CONST(band1_scale, inside_scale_queen);
2755 static double const band1_y = CONST(band1_y, bottom_queen - inside_height - band1_height + band1_radius * band1_scale);
2756 static double const crown_bottom_left = CONST(crown_bottom_left, -crown_bottom_width / 2);
2757 static double const band2_radius = CONST(band2_radius ,band1_radius +
2758 (-band1_radius - crown_bottom_left) * band2_height / (band1_y - tooth_outside));
2759 static double const band2_scale = CONST(band2_scale, band1_scale);
2760 static double const band2_y = CONST(band2_y, bottom_queen - inside_height - band1_height - band2_height + band2_radius * band2_scale);
2761 static double const ball1_x = CONST(ball1_x, ball_right1 - ball_outside_diameter / 2);
2762 static double const ball2_x = CONST(ball2_x, ball_right2 - ball_outside_diameter / 2);
2763 static double const ball1_y = CONST(ball1_y, ball_top1 + ball_outside_diameter / 2);
2764 static double const ball2_y = CONST(ball2_y, ball_top2 + ball_outside_diameter / 2);
2765 static double const ball_radius_queen = CONST(ball_radius_queen, (ball_outside_diameter - black_line_width) / 2);
2771 static double const ball_center_y = CONST(ball_center_y,
2772 0.5 * (ball2_x * ball2_x + ball2_y * ball2_y - ball1_x * ball1_x - ball1_y * ball1_y) / (ball2_y - ball1_y));
2773 static double const ball3_y = CONST(ball3_y,
2774 ball_center_y - sqrt(ball1_x * ball1_x + (ball1_y - ball_center_y) * (ball1_y - ball_center_y)));
2776 static double const ball1_angle = CONST(ball1_angle, atan((0.5 * (crown_bottom_left + ball2_x) - ball1_x) / (tooth_outside - ball1_y)));
2777 static double const tooth1_x = CONST(tooth1_x, ball1_x + ball_radius_queen * sin(ball1_angle));
2778 static double const tooth2_x = CONST(tooth2_x, ball2_x);
2779 static double const tooth1_top = CONST(tooth1_top, ball1_y + ball_radius_queen * cos(ball1_angle));
2780 static double const tooth2_top = CONST(tooth2_top, ball2_y + ball_radius_queen);
2781 static double const tooth3_top = CONST(tooth3_top, ball3_y + ball_radius_queen);
2786 cairo_translate(cr, x, y);
2787 cairo_scale(cr, scale, scale);
2788 cairo_set_line_width(cr, black_line_width);
2792 for (
int stroke = 0; stroke < 2; ++stroke)
2795 cairo_move_to(cr, -tooth1_x, tooth1_top);
2796 cairo_line_to(cr, -crown_bottom_left, tooth_outside);
2797 cairo_line_to(cr, band1_radius, band1_y);
2802 cairo_translate(cr, 0.0, inside_y_queen);
2803 cairo_scale(cr, 1.0, inside_scale_queen);
2804 cairo_arc(cr, 0.0, 0.0, inside_radius_queen, 0.0, M_PI);
2808 cairo_line_to(cr, -band1_radius, band1_y);
2809 cairo_line_to(cr, crown_bottom_left, tooth_outside);
2810 cairo_line_to(cr, tooth1_x, tooth1_top);
2815 cairo_new_sub_path(cr);
2816 cairo_move_to(cr, tooth1_x, tooth1_top);
2820 cairo_line_to(cr, tooth2_x, tooth_inside);
2823 cairo_line_to(cr, tooth2_x, tooth2_top);
2827 cairo_new_sub_path(cr);
2828 cairo_move_to(cr, tooth2_x, tooth2_top);
2832 cairo_line_to(cr, tooth3_x, tooth_inside2);
2835 cairo_line_to(cr, 0.0, tooth3_top);
2839 cairo_new_sub_path(cr);
2840 cairo_move_to(cr, 0.0, tooth3_top);
2844 cairo_line_to(cr, -tooth3_x, tooth_inside2);
2847 cairo_line_to(cr, -tooth2_x, tooth2_top);
2851 cairo_new_sub_path(cr);
2852 cairo_move_to(cr, -tooth2_x, tooth2_top);
2856 cairo_line_to(cr, -tooth2_x, tooth_inside);
2859 cairo_line_to(cr, -tooth1_x, tooth1_top);
2864 set_line_color(cr, priv, white);
2866 set_fill_color(cr, priv, white);
2871 set_fill_color(cr, priv, white);
2876 cairo_translate(cr, 0.0, inside_y_queen);
2877 cairo_scale(cr, 1.0, inside_scale_queen);
2878 cairo_arc(cr, 0.0, 0.0, inside_radius_queen, -M_PI, 0.0);
2881 cairo_new_sub_path(cr);
2885 cairo_translate(cr, 0.0, band1_y);
2886 cairo_scale(cr, 1.0, band1_scale);
2887 cairo_arc(cr, 0.0, 0.0, band1_radius, -M_PI, 0.0);
2890 set_line_color(cr, priv, white);
2895 cairo_set_line_width(cr, white_line_width);
2897 cairo_set_line_width(cr, black_line_width);
2904 cairo_arc(cr, ball1_x, ball1_y, ball_radius_queen, -M_PI, M_PI);
2907 set_fill_color(cr, priv, white);
2908 cairo_fill_preserve(cr);
2910 set_line_color(cr, priv, white);
2913 cairo_arc(cr, ball2_x, ball2_y, ball_radius_queen, -M_PI, M_PI);
2916 set_fill_color(cr, priv, white);
2917 cairo_fill_preserve(cr);
2919 set_line_color(cr, priv, white);
2922 cairo_arc(cr, 0.0, ball3_y, ball_radius_queen, -M_PI, M_PI);
2925 set_fill_color(cr, priv, white);
2926 cairo_fill_preserve(cr);
2928 set_line_color(cr, priv, white);
2931 cairo_arc(cr, -ball2_x, ball2_y, ball_radius_queen, -M_PI, M_PI);
2934 set_fill_color(cr, priv, white);
2935 cairo_fill_preserve(cr);
2937 set_line_color(cr, priv, white);
2940 cairo_arc(cr, -ball1_x, ball1_y, ball_radius_queen, -M_PI, M_PI);
2943 set_fill_color(cr, priv, white);
2944 cairo_fill_preserve(cr);
2946 set_line_color(cr, priv, white);
2953 static double const y0_queen = CONST(y0_queen, 0.0952);
2955 static double const ym = CONST(ym, 0.0331);
2958 static double const x0_queen = CONST(x0_queen, tooth1_x + (y0_queen - tooth1_top) * (crown_bottom_left - tooth1_x) / (tooth_outside - tooth1_top));
2960 static double const tilt_angle = CONST(tilt_angle, atan((ym - y0_queen) / x0_queen));
2964 static double const beta_queen = CONST(beta_queen, 1.202);
2966 static double const len = CONST(len, 0.1728);
2968 static double const py = CONST(py, len * cos(beta_queen));
2969 static double const y0_plus_py_cos_tilt_angle = CONST(y0_plus_py_cos_tilt_angle, y0_queen + py * cos(tilt_angle));
2970 static double const sin_tilt_angle = CONST(sin_tilt_angle, sin(tilt_angle));
2972 static double px_offset = CONST(px_offset, len * sin(beta_queen));
2974 cairo_move_to(cr, crown_bottom_left, tooth_outside);
2975 cairo_line_to(cr, x0_queen, y0_queen);
2979 for (
int i = 0; i < N; ++i)
2981 double const alpha = i * M_PI / N;
2983 double px2 = x0_queen * cos(alpha + px_offset);
2984 double pz2 = - x0_queen * sin(alpha + px_offset);
2985 double px3 = x0_queen * cos(alpha + M_PI / N - px_offset);
2986 double pz3 = - x0_queen * sin(alpha + M_PI / N - px_offset);
2987 double px4 = x0_queen * cos(alpha + M_PI / N);
2988 double pz4 = - x0_queen * sin(alpha + M_PI / N);
2991 double tpy2 = y0_plus_py_cos_tilt_angle - pz2 * sin_tilt_angle;
2992 double tpy3 = y0_plus_py_cos_tilt_angle - pz3 * sin_tilt_angle;
2993 double tpy4 = y0_queen - pz4 * sin_tilt_angle;
2994 cairo_curve_to(cr, px2, tpy2, px3, tpy3, px4, tpy4);
2997 cairo_line_to(cr, -crown_bottom_left, tooth_outside);
3002 cairo_translate(cr, 0.0, band2_y);
3003 cairo_scale(cr, 1.0, band2_scale);
3004 cairo_arc_negative(cr, 0.0, 0.0, band2_radius, -0.15, -M_PI + 0.15);
3009 cairo_close_path(cr);
3010 set_fill_color(cr, priv, white);
3011 cairo_fill_preserve(cr);
3014 cairo_set_line_width(cr, white_line_width);
3015 set_line_color(cr, priv, white);
3024 static double const width_rook_cm = CONST(width_rook_cm, 5.33);
3025 static double const foot_left_cm = CONST(foot_left_cm, 0.90);
3026 static double const base_left_cm = CONST(base_left_cm, 1.26);
3027 static double const tower_left_cm = CONST(tower_left_cm, 1.64);
3028 static double const opening_left_cm = CONST(opening_left_cm, 1.795);
3029 static double const opening_right_cm = CONST(opening_right_cm, 2.315);
3030 static double const height_rook_cm = CONST(height_rook_cm, 5.30);
3031 static double const bottom_rook_cm = CONST(bottom_rook_cm, 0.58);
3032 static double const foot_top_cm = CONST(foot_top_cm, 0.95);
3033 static double const base_top_cm = CONST(base_top_cm, 1.41);
3034 static double const tower_bottom_cm = CONST(tower_bottom_cm, 1.76);
3035 static double const tower_top_cm = CONST(tower_top_cm, 3.43);
3036 static double const top_bottom_cm = CONST(top_bottom_cm, 3.81);
3037 static double const opening_bottom_cm = CONST(opening_bottom_cm, 4.25);
3041 static double const foot_left = CONST(foot_left, -0.5 + foot_left_cm / width_rook_cm + 0.5 * black_line_width);
3042 static double const base_left = CONST(base_left, -0.5 + base_left_cm / width_rook_cm + 0.5 * black_line_width);
3043 static double const tower_left = CONST(tower_left, -0.5 + tower_left_cm / width_rook_cm + 0.5 * black_line_width);
3044 static double const opening_left = CONST(opening_left, -0.5 + opening_left_cm / width_rook_cm + 0.5 * black_line_width);
3045 static double const opening_right = CONST(opening_right, -0.5 + opening_right_cm / width_rook_cm + 0.5 * black_line_width);
3046 static double const bottom_rook = CONST(bottom_rook, 0.5 - bottom_rook_cm / height_rook_cm - 0.5 * black_line_width);
3047 static double const foot_top = CONST(foot_top, 0.5 - foot_top_cm / height_rook_cm - 0.5 * black_line_width);
3048 static double const base_top = CONST(base_top, 0.5 - base_top_cm / height_rook_cm - 0.5 * black_line_width);
3049 static double const tower_bottom = CONST(tower_bottom, 0.5 - tower_bottom_cm / height_rook_cm - 0.5 * black_line_width);
3050 static double const tower_top = CONST(tower_top, 0.5 - tower_top_cm / height_rook_cm - 0.5 * black_line_width);
3051 static double const top_bottom = CONST(top_bottom, 0.5 - top_bottom_cm / height_rook_cm - 0.5 * black_line_width);
3052 static double const opening_bottom = CONST(opening_bottom, 0.5 - opening_bottom_cm / height_rook_cm - 0.5 * black_line_width);
3055 static double const top_top = CONST(top_top, -bottom_rook);
3058 double const inner_line_width = white ? black_line_width : snap_line_width(white_line_width, scale);
3059 double const bottom_sn = snap_bottom(bottom_rook, y, scale, black_line_width);
3060 double const foot_top_sn = snap_bottom(foot_top, y, scale, inner_line_width);
3061 double const base_top_sn = snap_bottom(base_top, y, scale, inner_line_width);
3062 double const tower_bottom_sn = snap_bottom(tower_bottom, y, scale, inner_line_width);
3063 double const tower_top_sn = snap_top(tower_top, y, scale, inner_line_width);
3064 double const top_bottom_sn = snap_top(top_bottom, y, scale, inner_line_width);
3065 double const opening_bottom_sn = snap_top(opening_bottom, y, scale, black_line_width);
3066 double const top_top_sn = snap_top(top_top, y, scale, black_line_width);
3071 cairo_translate(cr, x, y);
3072 cairo_scale(cr, scale, scale);
3073 cairo_set_line_width(cr, black_line_width);
3076 cairo_move_to(cr, foot_left, bottom_sn);
3077 cairo_line_to(cr, foot_left, foot_top_sn);
3078 cairo_line_to(cr, base_left, foot_top_sn);
3079 cairo_line_to(cr, base_left, base_top_sn);
3080 cairo_line_to(cr, tower_left, tower_bottom_sn);
3081 cairo_line_to(cr, tower_left, tower_top_sn);
3082 cairo_line_to(cr, base_left, top_bottom_sn);
3083 cairo_line_to(cr, base_left, top_top_sn);
3086 cairo_line_to(cr, opening_left, top_top_sn);
3087 cairo_line_to(cr, opening_left, opening_bottom_sn);
3088 cairo_line_to(cr, opening_right, opening_bottom_sn);
3089 cairo_line_to(cr, opening_right, top_top_sn);
3090 cairo_line_to(cr, -opening_right, top_top_sn);
3091 cairo_line_to(cr, -opening_right, opening_bottom_sn);
3092 cairo_line_to(cr, -opening_left, opening_bottom_sn);
3093 cairo_line_to(cr, -opening_left, top_top_sn);
3094 cairo_line_to(cr, -base_left, top_top_sn);
3097 cairo_line_to(cr, -base_left, top_bottom_sn);
3098 cairo_line_to(cr, -tower_left, tower_top_sn);
3099 cairo_line_to(cr, -tower_left, tower_bottom_sn);
3100 cairo_line_to(cr, -base_left, base_top_sn);
3101 cairo_line_to(cr, -base_left, foot_top_sn);
3102 cairo_line_to(cr, -foot_left, foot_top_sn);
3103 cairo_line_to(cr, -foot_left, bottom_sn);
3106 cairo_close_path(cr);
3107 cairo_path_t* path = cairo_copy_path(cr);
3109 set_fill_color(cr, priv, white);
3113 cairo_move_to(cr, base_left + 0.5 * black_line_width, foot_top_sn);
3114 cairo_line_to(cr, -base_left - 0.5 * black_line_width, foot_top_sn);
3115 cairo_new_sub_path(cr);
3116 cairo_move_to(cr, base_left, base_top_sn);
3117 cairo_line_to(cr, -base_left, base_top_sn);
3118 cairo_new_sub_path(cr);
3119 cairo_move_to(cr, tower_left + (white ? 0.0 : (0.5 * black_line_width)), tower_bottom_sn);
3120 cairo_line_to(cr, -tower_left - (white ? 0.0 : (0.5 * black_line_width)), tower_bottom_sn);
3121 cairo_new_sub_path(cr);
3122 cairo_move_to(cr, tower_left + (white ? 0.0 : (0.5 * black_line_width)), tower_top_sn);
3123 cairo_line_to(cr, -tower_left - (white ? 0.0 : (0.5 * black_line_width)), tower_top_sn);
3124 cairo_new_sub_path(cr);
3125 cairo_move_to(cr, base_left + black_line_width * 0.5, top_bottom_sn);
3126 cairo_line_to(cr, -base_left - black_line_width * 0.5, top_bottom_sn);
3128 set_line_color(cr, priv, white);
3133 cairo_set_line_width(cr, inner_line_width);
3135 cairo_set_line_width(cr, black_line_width);
3138 cairo_append_path(cr, path);
3140 set_fill_color(cr, priv, white);
3143 cairo_path_destroy(path);
3151 static double const width_bishop_cm = CONST(width_bishop_cm, 5.34);
3152 static double const ribbon_width_cm = CONST(ribbon_width_cm, 0.49);
3153 static double const ribbon_bottom_left_cm = CONST(ribbon_bottom_left_cm, 0.72);
3154 static double const ribbon_top_left_cm = CONST(ribbon_top_left_cm, 2.28);
3155 static double const inside_outer_diameter_cm = CONST(inside_outer_diameter_cm, 2.0);
3156 static double const circle_diameter_cm = CONST(circle_diameter_cm, 2.44);
3157 static double const cross_width_cm = CONST(cross_width_cm, 0.93);
3158 static double const ball_outer_diameter_cm = CONST(ball_outer_diameter_cm, 0.81);
3159 static double const ball_inner_diameter_cm = CONST(ball_inner_diameter_cm, 0.41);
3160 static double const circle_start_angle = CONST(circle_start_angle, 0.767);
3161 static double const ribbon_end_angle = CONST(ribbon_end_angle, 1.097);
3162 static double const height_bishop_cm = CONST(height_bishop_cm, 5.44);
3163 static double const ribbon_bottom_y1_cm = CONST(ribbon_bottom_y1_cm, 0.52);
3164 static double const ribbon_bottom_y2_cm = CONST(ribbon_bottom_y2_cm, 0.76);
3165 static double const ribbon_bottom_y3_cm = CONST(ribbon_bottom_y3_cm, 0.55);
3166 static double const ribbon_top_y1_cm = CONST(ribbon_top_y1_cm, 0.99);
3167 static double const ribbon_top_y2_cm = CONST(ribbon_top_y2_cm, 1.25);
3168 static double const ribbon_inside_y_cm = CONST(ribbon_inside_y_cm, 0.93);
3169 static double const inside_bottom_cm = CONST(inside_bottom_cm, 1.34);
3170 static double const inside_top_cm = CONST(inside_top_cm, 1.86);
3171 static double const band_top_bishop_cm = CONST(band_top_bishop_cm, 2.34);
3172 static double const circle_y_cm = CONST(circle_y_cm, 3.11);
3173 static double const cross_y_bishop_cm = CONST(cross_y_bishop_cm, 3.24);
3174 static double const point_y_cm = CONST(point_y_cm, 4.47);
3175 static double const ball_y_cm = CONST(ball_y_cm, 4.675);
3176 static double const sp1_x_cm = CONST(sp1_x_cm, 2.1);
3177 static double const sp1_y_cm = CONST(sp1_y_cm, 3.95);
3178 static double const ribbon_bottom_x1_cm = CONST(ribbon_bottom_x1_cm, 3.34);
3179 static double const ribbon_bottom_x2_cm = CONST(ribbon_bottom_x2_cm, 4.1);
3180 static double const ribbon_top_x1_cm = CONST(ribbon_top_x1_cm, 3.54);
3181 static double const ribbon_top_x2_cm = CONST(ribbon_top_x2_cm, 4.24);
3184 static double const ribbon_width = CONST(ribbon_width, ribbon_width_cm / height_bishop_cm);
3185 static double const ribbon_bottom_left = CONST(ribbon_bottom_left, -0.5 + ribbon_bottom_left_cm / width_bishop_cm);
3186 static double const ribbon_bottom_x1 = CONST(ribbon_bottom_x1, -0.5 + ribbon_bottom_x1_cm / width_bishop_cm);
3187 static double const ribbon_bottom_x2 = CONST(ribbon_bottom_x2, -0.5 + ribbon_bottom_x2_cm / width_bishop_cm);
3188 static double const ribbon_top_x1 = CONST(ribbon_top_x1, -0.5 + ribbon_top_x1_cm / width_bishop_cm);
3189 static double const ribbon_top_x2 = CONST(ribbon_top_x2, -0.5 + ribbon_top_x2_cm / width_bishop_cm);
3190 static double const ribbon_top_left = CONST(ribbon_top_left, -0.5 + ribbon_top_left_cm / width_bishop_cm);
3191 static double const inside_radius_bishop = CONST(inside_radius_bishop, 0.5 * (inside_outer_diameter_cm / width_bishop_cm - black_line_width));
3192 static double const circle_radius = CONST(circle_radius, 0.5 * circle_diameter_cm / width_bishop_cm);
3193 static double const cross_leg = CONST(cross_leg, 0.5 * cross_width_cm / width_bishop_cm);
3194 static double const ball_radius_bishop = CONST(ball_radius_bishop, 0.25 * (ball_outer_diameter_cm + ball_inner_diameter_cm) / width_bishop_cm);
3195 static double const ball_line_width = CONST(ball_line_width, black_line_width);
3196 static double const ribbon_bottom_y1 = CONST(ribbon_bottom_y1, 0.5 - ribbon_bottom_y1_cm / height_bishop_cm - 0.5 * black_line_width);
3197 static double const ribbon_bottom_y2 = CONST(ribbon_bottom_y2, 0.5 - ribbon_bottom_y2_cm / height_bishop_cm + 0.5 * black_line_width);
3198 static double const ribbon_bottom_y3 = CONST(ribbon_bottom_y3, 0.5 - ribbon_bottom_y3_cm / height_bishop_cm);
3199 static double const ribbon_inside_y = CONST(ribbon_inside_y, 0.5 - ribbon_inside_y_cm / height_bishop_cm);
3200 static double const ribbon_top_y1 = CONST(ribbon_top_y1, 0.5 - ribbon_top_y1_cm / height_bishop_cm - 0.5 * black_line_width);
3201 static double const ribbon_top_y2 = CONST(ribbon_top_y2, 0.5 - ribbon_top_y2_cm / height_bishop_cm + 0.5 * black_line_width);
3202 static double const inside_scale_bishop = CONST(inside_scale_bishop, ((inside_top_cm - inside_bottom_cm) / height_bishop_cm - black_line_width) / (2 * inside_radius_bishop));
3203 static double const inside_y_bishop = CONST(inside_y_bishop, 0.5 - 0.5 * (inside_top_cm + inside_bottom_cm) / height_bishop_cm);
3204 static double const inside_bottom = CONST(inside_bottom, 0.5 - inside_bottom_cm / height_bishop_cm - 0.5 * black_line_width);
3205 static double const band_top_bishop = CONST(band_top_bishop, 0.5 - band_top_bishop_cm / height_bishop_cm + 0.5 * black_line_width);
3206 static double const circle_y = CONST(circle_y, 0.5 - circle_y_cm / height_bishop_cm);
3207 static double const cross_y_bishop = CONST(cross_y_bishop, 0.5 - cross_y_bishop_cm / height_bishop_cm);
3208 static double const point_y = CONST(point_y, 0.5 - point_y_cm / height_bishop_cm);
3209 static double const ball_y = CONST(ball_y, 0.5 - ball_y_cm / height_bishop_cm);
3210 static double const inside_angle = CONST(inside_angle, acos(-ribbon_top_left / inside_radius_bishop));
3211 static double const sp1_x = CONST(sp1_x, -0.5 + sp1_x_cm / width_bishop_cm);
3212 static double const sp1_y = CONST(sp1_y, 0.5 - sp1_y_cm / height_bishop_cm);
3215 static double const spline_magic = CONST(spline_magic, 0.551784);
3216 static double const cp2_x = CONST(cp2_x, ribbon_bottom_y1 - ribbon_inside_y);
3217 static double const sp2_x = CONST(sp2_x, spline_magic * cp2_x);
3218 static double const sp2_y = CONST(sp2_y, ribbon_inside_y + spline_magic * (ribbon_bottom_y1 - ribbon_inside_y));
3219 static double const sp3_x = CONST(sp3_x, ribbon_bottom_x1 - spline_magic * (ribbon_bottom_x1 - cp2_x));
3220 static double const sp3_y = CONST(sp3_y, ribbon_bottom_y1);
3221 static double const sp4_x = CONST(sp4_x, ribbon_bottom_x1 + spline_magic * (ribbon_bottom_x2 - ribbon_bottom_x1));
3222 static double const sp4_y = CONST(sp4_y, ribbon_bottom_y1);
3223 static double const sp5_x = CONST(sp5_x, ribbon_bottom_x2 - spline_magic * (ribbon_bottom_x2 - ribbon_bottom_x1));
3224 static double const sp5_y = CONST(sp5_y, ribbon_bottom_y2);
3225 static double const cp6_x = CONST(cp6_x, -ribbon_bottom_left - (ribbon_bottom_y3 - ribbon_bottom_y2) * tan(ribbon_end_angle));
3226 static double const sp6_x = CONST(sp6_x, ribbon_bottom_x2 + spline_magic * (cp6_x - ribbon_bottom_x2));
3227 static double const sp6_y = CONST(sp6_y, ribbon_bottom_y2);
3228 static double const sp7_x = CONST(sp7_x, -ribbon_bottom_left - spline_magic * (-ribbon_bottom_left - cp6_x));
3229 static double const sp7_y = CONST(sp7_y, ribbon_bottom_y3 - spline_magic * (ribbon_bottom_y3 - ribbon_bottom_y2));
3230 static double const ribbon_end_top_x = CONST(ribbon_end_top_x, -ribbon_bottom_left + ribbon_width * cos(ribbon_end_angle));
3231 static double const ribbon_end_top_y = CONST(ribbon_end_top_y, ribbon_bottom_y3 - ribbon_width * sin(ribbon_end_angle));
3232 static double const cp8_x = CONST(cp8_x, ribbon_end_top_x - (ribbon_end_top_y - ribbon_top_y2) * tan(ribbon_end_angle));
3233 static double const sp8_x = CONST(sp8_x, ribbon_end_top_x - spline_magic * (ribbon_end_top_x - cp8_x));
3234 static double const sp8_y = CONST(sp8_y, ribbon_end_top_y - spline_magic * (ribbon_end_top_y - ribbon_top_y2));
3235 static double const sp9_x = CONST(sp9_x, ribbon_top_x2 + spline_magic * (cp8_x - ribbon_top_x2));
3236 static double const sp9_y = CONST(sp9_y, ribbon_top_y2);
3237 static double const sp10_x = CONST(sp10_x, ribbon_top_x2 - spline_magic * (ribbon_top_x2 - ribbon_top_x1));
3238 static double const sp10_y = CONST(sp10_y, ribbon_top_y2);
3239 static double const sp11_x = CONST(sp11_x, ribbon_top_x1 + spline_magic * (ribbon_top_x2 - ribbon_top_x1));
3240 static double const sp11_y = CONST(sp11_y, ribbon_top_y1);
3241 static double const ribbon_top_y3 = CONST(ribbon_top_y3, 0.2695);
3242 static double const sp12_x = CONST(sp12_x, ribbon_top_x1 - spline_magic * (ribbon_top_x1 + ribbon_top_left));
3243 static double const sp12_y = CONST(sp12_y, ribbon_top_y1);
3244 static double const sp13_x = CONST(sp13_x, -ribbon_top_left);
3245 static double const sp13_y = CONST(sp13_y, ribbon_top_y3 + 0.509 * spline_magic * (ribbon_top_y1 - ribbon_top_y3));
3250 cairo_translate(cr, x, y);
3251 cairo_scale(cr, scale, scale);
3252 cairo_set_line_width(cr, black_line_width);
3257 cairo_move_to(cr, -ribbon_top_x1, ribbon_top_y1);
3258 cairo_curve_to(cr, -sp11_x, sp11_y, -sp10_x, sp10_y, -ribbon_top_x2, ribbon_top_y2);
3261 cairo_curve_to(cr, -sp9_x, sp9_y, -sp8_x, sp8_y, -ribbon_end_top_x, ribbon_end_top_y);
3264 cairo_line_to(cr, ribbon_bottom_left, ribbon_bottom_y3);
3267 cairo_curve_to(cr, -sp7_x, sp7_y, -sp6_x, sp6_y, -ribbon_bottom_x2, ribbon_bottom_y2);
3270 cairo_curve_to(cr, -sp5_x, sp5_y, -sp4_x, sp4_y, -ribbon_bottom_x1, ribbon_bottom_y1);
3273 cairo_curve_to(cr, -sp3_x, sp3_y, -sp2_x, sp2_y, 0.0, ribbon_inside_y);
3276 cairo_curve_to(cr, sp2_x, sp2_y, sp3_x, sp3_y, ribbon_bottom_x1, ribbon_bottom_y1);
3279 cairo_curve_to(cr, sp4_x, sp4_y, sp5_x, sp5_y, ribbon_bottom_x2, ribbon_bottom_y2);
3282 cairo_curve_to(cr, sp6_x, sp6_y, sp7_x, sp7_y, -ribbon_bottom_left, ribbon_bottom_y3);
3285 cairo_line_to(cr, ribbon_end_top_x, ribbon_end_top_y);
3288 cairo_curve_to(cr, sp8_x, sp8_y, sp9_x, sp9_y, ribbon_top_x2, ribbon_top_y2);
3291 cairo_curve_to(cr, sp10_x, sp10_y, sp11_x, sp11_y, ribbon_top_x1, ribbon_top_y1);
3295 set_fill_color(cr, priv, white);
3296 cairo_fill_preserve(cr);
3298 cairo_move_to(cr, ribbon_top_x1, ribbon_top_y1);
3302 cairo_curve_to(cr, sp12_x, sp12_y, sp13_x, sp13_y, -ribbon_top_left, ribbon_top_y3);
3306 cairo_translate(cr, 0.0, inside_y_bishop);
3307 cairo_scale(cr, 1.0, inside_scale_bishop);
3308 cairo_arc(cr, 0.0, 0.0, inside_radius_bishop, inside_angle, M_PI - inside_angle);
3312 cairo_line_to(cr, ribbon_top_left, ribbon_top_y3);
3315 cairo_curve_to(cr, -sp13_x, sp13_y, -sp12_x, sp12_y, -ribbon_top_x1 + 0.01 * black_line_width, ribbon_top_y1);
3316 cairo_close_path(cr);
3319 set_fill_color(cr, priv, white);
3321 set_line_color(cr, priv, white);
3322 cairo_fill_preserve(cr);
3324 set_line_color(cr, priv, white);
3326 set_fill_color(cr, priv, white);
3330 cairo_move_to(cr, 0.0, inside_bottom);
3331 cairo_line_to(cr, 0.0, ribbon_inside_y);
3337 cairo_translate(cr, 0.0, inside_y_bishop);
3338 cairo_scale(cr, 1.0, inside_scale_bishop);
3339 cairo_arc(cr, 0.0, 0.0, inside_radius_bishop, 0.0, -M_PI);
3342 cairo_arc(cr, 0.0, circle_y, circle_radius, -M_PI - circle_start_angle, -M_PI);
3344 cairo_curve_to(cr, -circle_radius, circle_y - 0.0848, sp1_x - 0.02657, sp1_y + 0.01722, sp1_x, sp1_y);
3345 cairo_curve_to(cr, sp1_x + 0.08845, sp1_y - 0.05733, -0.000333, point_y + 0.000265, 0.0, point_y);
3346 cairo_curve_to(cr, 0.000333, point_y + 0.000265, -sp1_x - 0.08845, sp1_y - 0.05733, -sp1_x, sp1_y);
3347 cairo_curve_to(cr, -sp1_x + 0.02657, sp1_y + 0.01722, circle_radius, circle_y - 0.0848, circle_radius, circle_y);
3349 cairo_arc(cr, 0.0, circle_y, circle_radius, 0.0, circle_start_angle);
3351 cairo_close_path(cr);
3354 set_fill_color(cr, priv, white);
3355 cairo_fill_preserve(cr);
3357 set_line_color(cr, priv, white);
3362 set_line_color(cr, priv, white);
3366 static double const x2_bishop = CONST(x2_bishop, -circle_radius * cos(circle_start_angle));
3367 static double const y2_bishop = CONST(y2_bishop, (circle_y + circle_radius * sin(circle_start_angle)));
3368 cairo_move_to(cr, -inside_radius_bishop, inside_y_bishop);
3369 cairo_line_to(cr, x2_bishop, y2_bishop);
3370 cairo_line_to(cr, -x2_bishop, y2_bishop);
3371 cairo_line_to(cr, inside_radius_bishop, inside_y_bishop);
3372 cairo_close_path(cr);
3376 cairo_translate(cr, 0.0, inside_y_bishop);
3377 cairo_scale(cr, 1.0, inside_scale_bishop);
3378 cairo_arc(cr, 0.0, 0.0, inside_radius_bishop, -M_PI, 0.0);
3384 cairo_set_line_width(cr, white_line_width);
3386 cairo_set_line_width(cr, black_line_width);
3398 static double const x1 = CONST(x1, -inside_radius_bishop);
3399 static double const y1 = CONST(y1, inside_y_bishop / -inside_scale_bishop);
3400 static double const x2 = CONST(x2, -circle_radius * cos(circle_start_angle));
3401 static double const y2 = CONST(y2, (circle_y + circle_radius * sin(circle_start_angle)) / -inside_scale_bishop);
3402 static double const d = CONST(d, sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)));
3403 static double const u1 = CONST(u1, (x2 - x1) / d);
3404 static double const u2 = CONST(u2, (y2 - y1) / d);
3405 static double const x0 = CONST(x0, x1 + (x2 - x1) * (0 - y1) / (y2 - y1));
3417 static double const y0 = CONST(y0, (band_top_bishop / -inside_scale_bishop + x0 * u2) / (1 - u1));
3418 static double const band_radius = CONST(band_radius, band_top_bishop / -inside_scale_bishop - y0);
3419 static double const angle = CONST(angle, atan(u1 / u2));
3421 cairo_scale(cr, 1.0, -inside_scale_bishop);
3424 static double const t2 = CONST(t2, x0 * u2 + u1 * y0);
3425 static double const t1 = CONST(t1, (y0 - u1 * t2) / u2);
3426 static double const x = CONST(x, x0 + u1 * t1);
3427 cairo_move_to(cr, x, y0);
3428 cairo_line_to(cr, x + d * u1, y0 + d * u2);
3429 cairo_line_to(cr, -x - d * u1, y0 + d * u2);
3430 cairo_line_to(cr, -x, y0);
3431 cairo_close_path(cr);
3434 cairo_arc(cr, 0.0, y0, band_radius, angle, M_PI - angle);
3436 cairo_scale(cr, 1.0, -1.0 / inside_scale_bishop);
3441 cairo_set_line_width(cr, white_line_width);
3443 cairo_set_line_width(cr, black_line_width);
3448 cairo_move_to(cr, -cross_leg, cross_y_bishop);
3449 cairo_line_to(cr, cross_leg, cross_y_bishop);
3450 cairo_move_to(cr, 0.0, cross_y_bishop - cross_leg);
3451 cairo_line_to(cr, 0.0, cross_y_bishop + cross_leg);
3456 cairo_set_line_width(cr, white_line_width);
3458 cairo_set_line_width(cr, black_line_width);
3463 cairo_move_to(cr, -inside_radius_bishop, inside_y_bishop);
3464 cairo_arc(cr, 0.0, circle_y, circle_radius, -M_PI - circle_start_angle, -M_PI);
3465 cairo_move_to(cr, inside_radius_bishop, inside_y_bishop);
3466 cairo_arc_negative(cr, 0.0, circle_y, circle_radius, circle_start_angle, 0.0);
3467 set_fill_color(cr, priv, white);
3472 cairo_set_line_width(cr, ball_line_width);
3473 cairo_arc(cr, 0.0, ball_y, ball_radius_bishop, -M_PI, M_PI);
3475 set_fill_color(cr, priv, white);
3476 cairo_fill_preserve(cr);
3478 set_line_color(cr, priv, white);
3487 static double const height_knight_cm = CONST(height_knight_cm, 21.9);
3488 static double const pixels_per_cm = CONST(pixels_per_cm, 32.467);
3489 static double const min_nose_x_px = CONST(min_nose_x_px, 8.0);
3490 static double const right_ear_y_px = CONST(right_ear_y_px, 15.0);
3491 static double const bottom_right_x_px = CONST(bottom_right_x_px, 582.82);
3492 static double const bottom_right_y_px = CONST(bottom_right_y_px, 580.82);
3493 static double const bottom_left_x_px = CONST(bottom_left_x_px, 190.00);
3495 static double const pixel_scale = CONST(pixel_scale, 1.0 / (pixels_per_cm * height_knight_cm));
3496 static double const knight_black_line_width = CONST(knight_black_line_width, 0.95 * black_line_width / pixel_scale);
3497 static double const knight_white_line_width = CONST(knight_white_line_width, 1.3 * knight_black_line_width);
3498 static double const knight_white_glyp_line_width = CONST(knight_white_glyp_line_width, knight_white_line_width - knight_black_line_width);
3501 static double const max_y = CONST(max_y, bottom_right_y_px * pixel_scale);
3502 static double const min_y = CONST(min_y, right_ear_y_px * pixel_scale);
3503 static double const max_x = CONST(max_x, bottom_right_x_px * pixel_scale);
3504 static double const min_x = CONST(min_x, min_nose_x_px * pixel_scale);
3507 static double const pixel_translate_x = CONST(pixel_translate_x, -(max_x + min_x) / 2);
3508 static double const pixel_translate_y = CONST(pixel_translate_y, -(max_y + min_y) / 2);
3513 cairo_translate(cr, x, y);
3514 cairo_scale(cr, scale, scale);
3519 cairo_translate(cr, pixel_translate_x, pixel_translate_y);
3521 cairo_scale(cr, pixel_scale, pixel_scale);
3524 cairo_move_to(cr, 319.00, 299.00);
3525 cairo_curve_to(cr, 322.00, 449.00, 165.00, 445.00, 192.00, 570.00);
3526 cairo_curve_to(cr, 192.00, 570.00, 568.50, 571.00, 568.50, 571.00);
3527 cairo_curve_to(cr, 577.00, 426.00, 533.00, 99.00, 340.50, 88.50);
3528 cairo_curve_to(cr, 245.50, 87.50, 206.00, 86.00, 195.00, 102.00);
3529 set_fill_color(cr, priv, white);
3533 cairo_move_to(cr, 315.00, 300.33);
3534 cairo_curve_to(cr, 301.43, 300.80, 291.75, 314.52, 282.00, 325.00);
3535 cairo_curve_to(cr, 298.67, 317.33, 316.33, 325.00, 317.33, 344.33);
3536 cairo_curve_to(cr, 321.33, 337.33, 326.00, 326.00, 315.00, 300.33);
3538 set_line_color(cr, priv, white);
3543 static double const back_top_offset = CONST(back_top_offset, (93.00 - knight_black_line_width) - 82.00);
3544 cairo_move_to(cr, 582.82, 580.82);
3545 cairo_curve_to(cr, 589.00, 359.00, 530.00,85.00, 332.00, 82.00 + back_top_offset);
3546 cairo_curve_to(cr, 320.87, 82.04 + back_top_offset, 314.25, 82.12 + back_top_offset, 302.50, 82.38 + back_top_offset);
3547 cairo_curve_to(cr, 302.75, 95.38, 296.22, 93.73, 319.50, 94.00);
3548 cairo_curve_to(cr, 510.50, 93.00, 556.12, 359.00, 556.12, 563.00);
3549 cairo_close_path(cr);
3553 cairo_move_to(cr, 190.00, 570.00);
3554 cairo_curve_to(cr, 190.00, 550.75, 190.00, 549.00, 190.00, 540.00);
3555 cairo_curve_to(cr, 190.00, 493.25, 210.50, 482.50, 285.00, 409.50);
3556 cairo_curve_to(cr, 298.25, 391.75, 313.00, 357.50, 317.75, 344.75);
3557 cairo_curve_to(cr, 320.25, 340.00, 320.25, 330.00, 320.00, 280.00);
3558 cairo_set_line_width(cr, knight_black_line_width);
3562 cairo_move_to(cr, 144.00, 31.50);
3563 cairo_curve_to(cr, 122.50, 67.00, 147.50, 57.50, 146.00, 105.00);
3564 cairo_curve_to(cr, 112.00, 125.50, 123.00, 140.50, 102.50, 170.00);
3565 cairo_curve_to(cr, 84.00, 199.50, 128.00, 181.50, 33.50, 313.50);
3566 cairo_curve_to(cr, -23.00, 414.00, 81.50, 468.00, 130.00, 447.50);
3567 cairo_curve_to(cr, 182.50, 398.00, 142.50, 427.00, 179.50, 390.00);
3568 cairo_curve_to(cr, 194.50, 376.50, 212.50, 349.50, 237.50, 347.00);
3569 cairo_curve_to(cr, 268.00, 344.00, 283.50, 323.50, 306.00, 301.00);
3570 cairo_curve_to(cr, 327.50, 276.50, 330.00, 264.50, 330.00, 228.50);
3572 set_fill_color(cr, priv, white);
3573 cairo_fill_preserve(cr);
3574 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
3576 set_line_color(cr, priv, white);
3578 cairo_move_to(cr, 201.00, 94.50);
3579 cairo_curve_to(cr, 184.50, 54.50, 152.00, 43.50, 144.00, 31.50);
3583 cairo_move_to(cr, 170.50, 136.50);
3584 cairo_curve_to(cr, 170.00, 129.50, 175.50, 125.00, 183.50, 116.00);
3585 cairo_curve_to(cr, 204.50, 91.00, 216.00, 94.00, 238.00, 91.00);
3591 cairo_move_to(cr, 529.00, 570.00);
3592 cairo_curve_to(cr, 530.50, 352.00, 476.50, 128.50, 334.00, 121.00);
3593 cairo_curve_to(cr, 310.50, 118.50, 310.00, 117.50, 296.50, 117.50);
3594 cairo_curve_to(cr, 291.50, 100.00, 252.50, 95.50, 242.20, 119.35);
3595 cairo_curve_to(cr, 227.55, 120.95, 212.22, 124.23, 198.50, 130.50);
3596 cairo_curve_to(cr, 178.00, 137.50, 158.50, 147.50, 154.00, 137.00);
3597 cairo_curve_to(cr, 149.50, 127.00, 145.50, 121.00, 204.00, 100.00);
3598 cairo_curve_to(cr, 226.50, 90.00, 276.50, 92.00, 319.50, 94.00);
3599 cairo_curve_to(cr, 510.50, 93.00, 556.00, 354.00, 556.00, 570.00);
3600 cairo_curve_to(cr, 548.06, 571.00, 537.73, 569.45, 529.00, 570.00);
3601 set_line_color(cr, priv, white);
3606 double dummy = bottom_left_x_px;
3607 double bottom_right_y_px_sn = bottom_right_y_px;
3611 cairo_user_to_device(cr,& dummy,& bottom_right_y_px_sn);
3612 bottom_right_y_px_sn = round(bottom_right_y_px_sn);
3613 cairo_device_to_user(cr,& dummy,& bottom_right_y_px_sn);
3615 cairo_rectangle(cr, bottom_left_x_px - 0.5 * knight_black_line_width,
3616 bottom_right_y_px_sn - knight_black_line_width,
3617 bottom_right_x_px - (bottom_left_x_px - 0.5 * knight_black_line_width),
3618 knight_black_line_width);
3620 set_fill_color(cr, priv, white);
3624 cairo_move_to(cr, 113.67, 389.33);
3625 cairo_curve_to(cr, 121.00, 388.00, 129.33, 406.67, 120.67, 414.67);
3626 cairo_curve_to(cr, 114.33, 419.33, 104.33, 431.00, 112.67, 444.00);
3628 cairo_line_to(cr, 93.00, 446.67);
3629 cairo_curve_to(cr, 89.00, 418.67, 94.67, 417.33, 100.00, 412.67);
3630 cairo_curve_to(cr, 112.67, 402.00, 100.67, 394.67, 113.67, 389.33);
3632 set_line_color(cr, priv, white);
3637 cairo_fill_preserve(cr);
3638 cairo_set_line_width(cr, knight_white_glyp_line_width);
3640 cairo_set_line_width(cr, knight_black_line_width);
3644 cairo_move_to(cr, 33.50, 313.50);
3645 cairo_curve_to(cr, -23.00, 414.00, 81.50, 468.00, 130.00, 447.50);
3647 set_fill_color(cr, priv, white);
3653 cairo_move_to(cr, 312.32, 293.46);
3654 cairo_curve_to(cr, 328.01, 273.63, 330.00, 260.62, 330.00, 228.50);
3655 cairo_set_line_width(cr, knight_white_line_width);
3656 set_line_color(cr, priv, white);
3658 cairo_set_line_width(cr, knight_black_line_width);
3662 for (
int stroke = 0; stroke < 2; ++stroke)
3664 cairo_move_to(cr, 242.00, 114.00);
3665 cairo_curve_to(cr, 235.00, 76.00, 235.50, 92.50, 267.00, 15.00);
3667 cairo_move_to(cr, 267.00, 15.00);
3668 cairo_curve_to(cr, 309.50, 85.50, 312.00, 88.00, 295.00, 117.00);
3672 set_line_color(cr, priv, white);
3678 set_fill_color(cr, priv, white);
3680 set_fill_color(cr, priv, white);
3686 set_line_color(cr, priv, white);
3689 cairo_move_to(cr, 76.00, 363.00);
3690 cairo_curve_to(cr, 66.00, 372.33, 78.33, 379.00, 66.00, 384.00);
3691 cairo_curve_to(cr, 21.00, 399.00, 61.67, 331.00, 79.67, 341.67);
3692 cairo_curve_to(cr, 81.00, 342.00, 84.67, 353.33, 76.00, 363.00);
3697 cairo_fill_preserve(cr);
3698 cairo_set_line_width(cr, knight_white_glyp_line_width);
3700 cairo_set_line_width(cr, knight_black_line_width);
3704 cairo_move_to(cr, 173.33, 208.00);
3705 cairo_curve_to(cr, 180.67, 207.00, 182.00, 197.67, 182.00, 197.67);
3706 cairo_curve_to(cr, 184.59, 176.98, 182.28, 177.30, 190.67, 173.00);
3707 cairo_curve_to(cr, 201.00, 169.33, 198.33, 146.00, 173.33, 161.67);
3708 cairo_curve_to(cr, 146.00, 181.33, 130.67, 192.00, 128.33, 202.67);
3709 cairo_curve_to(cr, 124.00, 233.33, 131.00, 227.33, 144.67, 207.00);
3710 cairo_curve_to(cr, 150.67, 201.00, 158.67, 193.67, 162.33, 203.33);
3711 cairo_curve_to(cr, 164.67, 206.00, 165.63, 209.29, 173.33, 208.00);
3716 cairo_fill_preserve(cr);
3717 cairo_set_line_width(cr, knight_white_glyp_line_width);
3727 static gboolean cw_chessboard_motion_notify(GtkWidget* widget, GdkEventMotion* event)
3729 Dout(dc::motion_event,
"Calling cw_chessboard_motion_notify(" << widget <<
", " << event <<
")");
3730 update_cursor_position(CW_CHESSBOARD(widget), event->x, event->y, FALSE);
3735 static gboolean cw_chessboard_default_motion_notify(GtkWidget* widget, GdkEventMotion* event)
3737 Dout(dc::motion_event,
"Calling cw_chessboard_default_motion_notify(" << widget <<
", " << event <<
")");
3742 if (priv->floating_piece_handle != -1)
3744 double hsside = 0.5 * chessboard->
sside;
3745 double fraction = hsside - (gint)hsside;
void cw_chessboard_set_square(CwChessboard* chessboard, gint col, gint row, CwChessboardCode code)
CwChessboardCode const white_bishop
void cw_chessboard_set_cursor_thickness(CwChessboard* chessboard, gdouble thickness)
CwChessboardCode const empty_square
gint const sside
Square side in pixels (read only).
void cw_chessboard_get_border_color(CwChessboard* chessboard, GdkColor* color)
uint16_t CwChessboardCode
A code to specify a chess piece.
gboolean cw_chessboard_get_active_turn_indicator(CwChessboard* chessboard)
void cw_chessboard_free_color_handle(CwChessboard* chessboard, CwChessboardColorHandle handle)
void cw_chessboard_draw_knight(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
uint8_t const row_mask
A mask for the bits used for the row in IndexData.
ColorData const white
A constant representing the color white.
CWCHESSBOARD_INLINE gint cw_chessboard_x2col(CwChessboard* chessboard, gdouble x)
void cw_chessboard_set_white_line_color(CwChessboard* chessboard, GdkColor const* color)
CwChessboardCode const black_queen
void cw_chessboard_draw_bishop(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
void(* draw_piece[6])(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble sside, gboolean white)
void cw_chessboard_draw_pawn(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
void cw_chessboard_set_background_colors(CwChessboard* chessboard, CwChessboardColorHandle const* handles)
CWCHESSBOARD_INLINE gint cw_chessboard_y2row(CwChessboard* chessboard, gdouble y)
CwChessboardCode const white_pawn
gboolean cw_chessboard_get_draw_border(CwChessboard* chessboard)
void cw_chessboard_get_white_line_color(CwChessboard* chessboard, GdkColor* color)
void cw_chessboard_default_draw_turn_indicator(CwChessboard* chessboard, gboolean white, gboolean on)
void(* draw_hud_layer)(CwChessboard* chessboard, cairo_t* cr, gint sside, guint hud)
This file contains the declaration of the GTK+ widget CwChessboard.
CwChessboardColorHandle cw_chessboard_allocate_color_handle_rgb(CwChessboard* chessboard, gdouble red, gdouble green, gdouble blue)
void cw_chessboard_draw_king(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
A GTK+ chessboard widget.
CwChessboardCode const white_queen
CwChessboardCode cw_chessboard_get_floating_piece(CwChessboard* chessboard, gint handle)
void cw_chessboard_default_draw_hud_layer(CwChessboard* chessboard, cairo_t* cr, gint sside, guint hud)
void cw_chessboard_set_marker_level(CwChessboard* chessboard, gboolean below)
void(* cursor_left_chessboard)(CwChessboard* chessboard, gint prev_col, gint prev_row)
void cw_chessboard_set_marker_thickness(CwChessboard* chessboard, gdouble thickness)
void cw_chessboard_default_draw_border(CwChessboard* chessboard)
gboolean cw_chessboard_get_draw_turn_indicators(CwChessboard* chessboard)
CwChessboardCode cw_chessboard_get_square(CwChessboard* chessboard, gint col, gint row)
void(* draw_turn_indicator)(CwChessboard* chessboard, gboolean white, gboolean on)
CwChessboardCode const black_pawn
CwChessboardCode const white_rook
gdouble cw_chessboard_get_cursor_thickness(CwChessboard* chessboard)
gint cw_chessboard_default_calc_board_border_width(CwChessboard const* chessboard, gint sside)
void cw_chessboard_draw_queen(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
void cw_chessboard_draw_rook(CwChessboard* chessboard, cairo_t* cr, gdouble x, gdouble y, gdouble scale, gboolean white)
void cw_chessboard_hide_cursor(CwChessboard* chessboard)
CwChessboardCode const black_bishop
void cw_chessboard_set_flip_board(CwChessboard* chessboard, gboolean flip)
void cw_chessboard_get_black_line_color(CwChessboard* chessboard, GdkColor* color)
unsigned char CwChessboardColorHandle
A color handle used for background markers.
CwChessboardCode const black_knight
void cw_chessboard_get_cursor_color(CwChessboard* chessboard, GdkColor* color)
CWCHESSBOARD_INLINE void cw_chessboard_colrow2xy(CwChessboard* chessboard, gint col, gint row, gint* x, gint* y)
The Class structure of CwChessboard.
void cw_chessboard_disable_hud_layer(CwChessboard* chessboard, guint hud)
gboolean(* draw_hud_square)(CwChessboard* chessboard, cairo_t* cr, gint col, gint row, gint sside, guint hud)
void cw_chessboard_set_draw_border(CwChessboard* chessboard, gboolean draw)
gpointer cw_chessboard_add_arrow(CwChessboard* chessboard, gint begin_col, gint begin_row, gint end_col, gint end_row, GdkColor const* color)
void cw_chessboard_get_light_square_color(CwChessboard* chessboard, GdkColor* color)
CwChessboardColorHandle cw_chessboard_get_marker_color(CwChessboard* chessboard, gint col, gint row)
gint const top_left_a1_y
The y coordinate of the top-left pixel of square a1 (read-only). Despite the name, if the board is flipped then it's square h8.
gint(* calc_board_border_width)(CwChessboard const* chessboard, gint sside)
void cw_chessboard_set_black_line_color(CwChessboard* chessboard, GdkColor const* color)
void(* draw_border)(CwChessboard* chessboard)
void cw_chessboard_set_white_fill_color(CwChessboard* chessboard, GdkColor const* color)
CwChessboardCode const white_knight
gint cw_chessboard_add_floating_piece(CwChessboard* chessboard, CwChessboardCode code, gdouble x, gdouble y, gboolean pointer_device)
void cw_chessboard_get_dark_square_color(CwChessboard* chessboard, GdkColor* color)
void cw_chessboard_set_border_color(CwChessboard* chessboard, GdkColor const* color)
void cw_chessboard_set_draw_turn_indicators(CwChessboard* chessboard, gboolean draw)
void cw_chessboard_set_dark_square_color(CwChessboard* chessboard, GdkColor const* color)
void cw_chessboard_set_cursor_color(CwChessboard* chessboard, GdkColor const* color)
CwChessboardCode const white_king
void cw_chessboard_set_black_fill_color(CwChessboard* chessboard, GdkColor const* color)
gboolean cw_chessboard_default_draw_hud_square(CwChessboard* chessboard, cairo_t* cr, gint col, gint row, gint sside, guint hud)
void(* cursor_entered_square)(CwChessboard* chessboard, gint prev_col, gint prev_row, gint col, gint row)
void cw_chessboard_get_white_fill_color(CwChessboard* chessboard, GdkColor* color)
void cw_chessboard_set_marker_color(CwChessboard* chessboard, gint col, gint row, CwChessboardColorHandle mahandle)
void cw_chessboard_move_floating_piece(CwChessboard* chessboard, gint handle, gdouble x, gdouble y)
GtkWidget * cw_chessboard_new(void)
void cw_chessboard_enable_hud_layer(CwChessboard* chessboard, guint hud)
void cw_chessboard_set_active_turn_indicator(CwChessboard* chessboard, gboolean white)
gboolean cw_chessboard_get_flip_board(CwChessboard* chessboard)
void cw_chessboard_show_cursor(CwChessboard* chessboard)
gdouble cw_chessboard_get_marker_thickness(CwChessboard* chessboard)
void cw_chessboard_remove_arrow(CwChessboard* chessboard, gpointer ptr)
CwChessboardColorHandle cw_chessboard_get_background_color(CwChessboard* chessboard, gint col, gint row)
This file contains the definitions of the CwChessboardCode constants.
gint const top_left_a1_x
The x coordinate of the top-left pixel of square a1 (read-only). Despite the name, if the board is flipped then it's square h8.
gboolean const flip_board
TRUE if the board is flipped (read-only).
void cw_chessboard_get_background_colors(CwChessboard* chessboard, CwChessboardColorHandle* handles)
void cw_chessboard_set_background_color(CwChessboard* chessboard, gint col, gint row, CwChessboardColorHandle bghandle)
uint8_t const col_mask
A mask for the bits used for the column in IndexData.
void cw_chessboard_set_light_square_color(CwChessboard* chessboard, GdkColor const* color)
CwChessboardCode const black_rook
void cw_chessboard_remove_floating_piece(CwChessboard* chessboard, gint handle)
void cw_chessboard_get_black_fill_color(CwChessboard* chessboard, GdkColor* color)
CwChessboardCode const black_king