/** * board.c * * A GTK+ widget that implements a backgammon board * */ #include #include #include "board.h" G_DEFINE_TYPE(BgBoard, bg_board, GTK_TYPE_DRAWING_AREA); static gboolean bg_board_expose(GtkWidget * board, GdkEventExpose * event); static void bg_board_class_init(BgBoardClass * class) { GtkWidgetClass *widget_class; widget_class = GTK_WIDGET_CLASS(class); widget_class->expose_event = bg_board_expose; } static void bg_board_init(BgBoard * board) { } static get_point_base(int i, int *x, int *y, int *direction) { if (i < 7) { *x = 220 + (6 - i) * 20; *y = 320; *direction = -1; } else if (i < 13) { *x = 80 + (12 - i) * 20; *y = 320; *direction = -1; } else if (i < 19) { *x = 80 + (i - 13) * 20; *y = 80; *direction = 1; } else if (i < 25) { *x = 220 + (i - 19) * 20; *y = 80; *direction = 1; } else { g_assert_not_reached(); } } static void draw_text(cairo_t * cr, int x, int y, double f, double size, const gchar * text) { PangoLayout *layout; PangoFontDescription *desc; gchar font_size[200]; g_ascii_formatd(font_size, sizeof(font_size), "%.1f", f * size); gchar *font_name = g_strdup_printf("Sans %s", font_size); int i; int width, height; /* Create a PangoLayout, set the font and text */ layout = pango_cairo_create_layout(cr); pango_layout_set_text(layout, text, -1); desc = pango_font_description_from_string(font_name); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); pango_layout_get_size(layout, &width, &height); cairo_move_to(cr, (x * f - width / 2.0 / PANGO_SCALE), (y * f - height / 2.0 / PANGO_SCALE)); pango_cairo_show_layout(cr, layout); cairo_stroke(cr); g_object_unref(layout); } static void draw_point(cairo_t * cr, double f, int i) { int x, y, direction; int even_point; double point_color; get_point_base(i, &x, &y, &direction); even_point = (i % 2); point_color = 1.0 - (double) even_point / 2.0; cairo_save(cr); cairo_translate(cr, x * f, y * f); cairo_move_to(cr, -10 * f, 0); cairo_line_to(cr, 0, direction * 100 * f); cairo_line_to(cr, 10 * f, 0); cairo_close_path(cr); cairo_set_source_rgb(cr, point_color, point_color, point_color); cairo_fill_preserve(cr); cairo_set_source_rgb(cr, 0, 0, 0); cairo_stroke(cr); cairo_move_to(cr, 0, 0); draw_text(cr, 0, -10 * direction, f, 9.0, g_strdup_printf("%d", i)); cairo_restore(cr); } static void draw_cube(cairo_t * cr, double f, int i) { int y; y = (i + 1) * 110 + 82; cairo_rectangle(cr, 192 * f, y * f, 16 * f, 16 * f); draw_text(cr, 200, y + 8, f, 9.0, "64"); cairo_stroke(cr); } static void draw_turn(cairo_t * cr, double f, int i) { cairo_rectangle(cr, 58 * f, 185 * f, 4 * f, 16 * f); cairo_fill(cr); cairo_move_to(cr, 53 * f, 201 * f); cairo_line_to(cr, 60 * f, 215 * f); cairo_line_to(cr, 67 * f, 201 * f); cairo_close_path(cr); cairo_fill(cr); } static void draw_checker(cairo_t * cr, double f, int player, int point, int c) { int i, x, y, direction, p; g_return_if_fail( c > 0 && c < 16); get_point_base(point, &x, &y, &direction); y -= 10*direction; for (p=0;c > 0 && p<5; c--,p++) { y += 20*direction; cairo_arc(cr, x*f, y*f, 10*f, 0, 2*M_PI); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill_preserve(cr); cairo_set_source_rgb(cr, 0, 0, 0); cairo_stroke(cr); } if (c) draw_text(cr, x, y, f, 8.0, g_strdup_printf("%d", c+5)); } static void draw_checkers(cairo_t * cr, double f) { int board[2][25] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }; int player, point, c; for (player = 0; player < 2; player++) { for (point = 0; point < 25; point++) { board[player][point] = 15; if (c = board[player][point]) draw_checker(cr, f, player, point, c); } } } static void draw_board(double x, double y, double size, cairo_t * cr) { int i; double f; f = size / 400.0; cairo_save(cr); cairo_set_line_width(cr, 2); cairo_rectangle(cr, 50 * f, 60 * f, 300 * f, 280 * f); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill_preserve(cr); cairo_set_source_rgb(cr, 0, 0, 0); cairo_rectangle(cr, 70 * f, 80 * f, 260 * f, 240 * f); cairo_rectangle(cr, 190 * f, 80 * f, 20 * f, 240 * f); cairo_rectangle(cr, 50 * f, 182 * f, 20 * f, 36 * f); cairo_rectangle(cr, 330 * f, 182 * f, 20 * f, 36 * f); cairo_stroke(cr); for (i = 1; i < 25; i++) draw_point(cr, f, i); for (i = -1; i < 2; i++) draw_cube(cr, f, i); draw_checkers(cr, f); draw_turn(cr, f, -1); cairo_restore(cr); } static void draw(GtkWidget * board, cairo_t * cr) { double x, y; double size; x = board->allocation.x; y = board->allocation.y; size = MIN(board->allocation.width, board->allocation.height); draw_board(x, y, size, cr); } static gboolean bg_board_expose(GtkWidget * board, GdkEventExpose * event) { cairo_t *cr; /* get a cairo_t */ cr = gdk_cairo_create(board->window); cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); //cairo_clip(cr); draw(board, cr); cairo_destroy(cr); return FALSE; } GtkWidget *bg_board_new(void) { return g_object_new(BG_TYPE_BOARD, NULL); }