X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=src%2Fgrr_board_view.c;fp=src%2Fgrr_board_view.c;h=a03a708e9a152b01231ca785993bb03a7fc9bf57;hb=e27bd3ce66f33bb5d60be05a8ffae485f1f1b584;hp=b48c2913e8a9cef451cc4311719d4a433b1789d8;hpb=f1cf379f7a0932549fde7ca0a2b86d05fcd7af62;p=grrobot diff --git a/src/grr_board_view.c b/src/grr_board_view.c index b48c291..a03a708 100644 --- a/src/grr_board_view.c +++ b/src/grr_board_view.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -66,7 +66,6 @@ static gint grr_board_view_motion_notify (GtkWidget *widget, GdkEventMotion *event); static void grr_board_view_update_mouse (grr_board_view_t *view, gint x, gint y); -static void grr_board_view_update (grr_board_view_t *view); /* Local data */ @@ -154,12 +153,22 @@ grr_board_view_t * grr_board_view_new (rr_board_t *board) { grr_board_view_t *view; + int x, y; view = g_object_new (grr_board_view_get_type (), NULL); view->board = board; + rr_board_get_size (board, &view->board_width, &view->board_height); + + view->damaged = malloc (view->board_height * sizeof (int *)); + for (y = 0; y < view->board_height; y++) { + view->damaged[y] = malloc (view->board_width * sizeof (int)); + for (x = 0; x< view->board_width; x++) { + view->damaged[y][x] = 1; + } + } - grr_board_view_update (view); + gtk_widget_queue_draw (GTK_WIDGET (view)); return view; } @@ -285,7 +294,7 @@ grr_board_view_size_allocate (GtkWidget *widget, static void grr_board_view_draw_walls (grr_board_view_t *view, - XrState *xrs, + cairo_t *xrs, rr_wall_t wall) { if (wall == RR_WALL_NONE) @@ -295,90 +304,24 @@ grr_board_view_draw_walls (grr_board_view_t *view, grr_icon_draw (view->wall_icon, xrs); } if (wall & RR_WALL_LEFT) { - XrSave (xrs); - XrRotate (xrs, M_PI_2); + cairo_save (xrs); + cairo_rotate (xrs, M_PI_2); grr_icon_draw (view->wall_icon, xrs); - XrRestore (xrs); + cairo_restore (xrs); } if (wall & RR_WALL_RIGHT) { - XrSave (xrs); - XrTranslate (xrs, GRR_SVG_ASSUMED_WIDTH, 0); - XrRotate (xrs, M_PI_2); + cairo_save (xrs); + cairo_translate (xrs, GRR_SVG_ASSUMED_WIDTH, 0); + cairo_rotate (xrs, M_PI_2); grr_icon_draw (view->wall_icon, xrs); - XrRestore (xrs); + cairo_restore (xrs); } if (wall & RR_WALL_BELOW) { - XrSave (xrs); - XrTranslate (xrs, 0, GRR_SVG_ASSUMED_HEIGHT); + cairo_save (xrs); + cairo_translate (xrs, 0, GRR_SVG_ASSUMED_HEIGHT); grr_icon_draw (view->wall_icon, xrs); - XrRestore (xrs); - } -} - -static void -grr_board_view_draw_cell (grr_board_view_t *view, - XrState *xrs, - rr_cell_t cell, - rr_target_t goal, - int width, - int height) -{ - int xpad, ypad; - rr_robot_t robot; - rr_target_t target; - - XrSave (xrs); - XrScale (xrs, - width / GRR_SVG_ASSUMED_WIDTH, - height / GRR_SVG_ASSUMED_HEIGHT); - grr_icon_draw (view->cell_icon, xrs); - grr_board_view_draw_walls (view, xrs, RR_CELL_GET_WALLS (cell)); - XrRestore (xrs); - - xpad = width / 10; - ypad = width / 10; - - XrSave (xrs); - XrTranslate (xrs, xpad, ypad); - XrScale (xrs, - (width - 2*xpad) / GRR_SVG_ASSUMED_WIDTH, - (height - 2*ypad) / GRR_SVG_ASSUMED_HEIGHT); - - target = RR_CELL_GET_TARGET (cell); - if (target) - grr_icon_draw (view->target_icon[rr_target_idx (target)], xrs); - - XrRestore (xrs); - - /* XXX: This is a kludge, (it obscures the cell background in - addition to the target). The real way to do this is to draw the - target itself with less opacity. */ - if (target && target != goal) { - XrSave (xrs); - XrScale (xrs, - width / GRR_SVG_ASSUMED_WIDTH, - height / GRR_SVG_ASSUMED_HEIGHT); - XrRectangle (xrs, 1, 1, - GRR_SVG_ASSUMED_WIDTH - 1, - GRR_SVG_ASSUMED_HEIGHT - 1); - XrSetRGBColor (xrs, 1, 1, 1); - XrSetAlpha (xrs, 0.75); - XrFill (xrs); - XrRestore (xrs); + cairo_restore (xrs); } - - XrSave (xrs); - XrTranslate (xrs, xpad, ypad); - XrScale (xrs, - (width - 2*xpad) / GRR_SVG_ASSUMED_WIDTH, - (height - 2*ypad) / GRR_SVG_ASSUMED_HEIGHT); - - robot = RR_CELL_GET_ROBOT (cell); - if (robot) - grr_icon_draw (view->robot_icon[rr_robot_idx (robot)], xrs); - - XrRestore (xrs); - } static gint @@ -389,7 +332,7 @@ grr_board_view_expose (GtkWidget *widget, rr_board_t *board; Display *dpy; Drawable drawable; - XrState *xrs; + cairo_t *xrs; GdkDrawable *real_drawable; gint x_off, y_off; int i, j; @@ -400,9 +343,6 @@ grr_board_view_expose (GtkWidget *widget, g_return_val_if_fail (GRR_IS_BOARD_VIEW (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); - if (event->count > 0) - return FALSE; - view = GRR_BOARD_VIEW (widget); board = view->board; @@ -411,11 +351,9 @@ grr_board_view_expose (GtkWidget *widget, dpy = gdk_x11_drawable_get_xdisplay (real_drawable); drawable = gdk_x11_drawable_get_xid (real_drawable); - /* Ignore GTK+ and use Xr for drawing. */ - xrs = XrCreate (); - XrSetTargetDrawable (xrs, dpy, drawable); - - rr_board_get_size (board, &view->board_width, &view->board_height); + /* Ignore GTK+ and use Cairo for drawing. */ + xrs = cairo_create (); + cairo_set_target_drawable (xrs, dpy, drawable); new_cell_width = widget->allocation.width / view->board_width; if (new_cell_width == 0) @@ -424,11 +362,6 @@ grr_board_view_expose (GtkWidget *widget, if (new_cell_height == 0) new_cell_height = 1; - view->cell_width = new_cell_width; - view->cell_height = new_cell_height; - - /* Pre-render icons if the size has changed */ - /* XXX: This code isn't fully baked yet if (new_cell_width != view->cell_width || new_cell_height != view->cell_height) { int i; @@ -438,8 +371,8 @@ grr_board_view_expose (GtkWidget *widget, view->cell_width = new_cell_width; view->cell_height = new_cell_height; - XrSave (xrs); - XrScale (xrs, + cairo_save (xrs); + cairo_scale (xrs, view->cell_width / GRR_SVG_ASSUMED_WIDTH, view->cell_height / GRR_SVG_ASSUMED_HEIGHT); @@ -461,69 +394,134 @@ grr_board_view_expose (GtkWidget *widget, view->cell_width, view->cell_height); } - XrRestore (xrs); + cairo_restore (xrs); + } + + view->cell_width = new_cell_width; + view->cell_height = new_cell_height; + + if (event->area.width) { + int x_start, y_start; + int x, y; + int x_stop, y_stop; + grr_board_view_transform_pixel_to_cell (view, + event->area.x, event->area.y, + &x_start, &y_start); + grr_board_view_transform_pixel_to_cell (view, + event->area.x + event->area.width - 1, + event->area.y + event->area.height - 1, + &x_stop, &y_stop); + for (y = y_start; y <= y_stop; y++) + for (x = x_start; x <= x_stop; x++) + view->damaged[y][x] = 1; } - */ - XrTranslate (xrs, -x_off, -y_off); + if (event->count > 0) + return FALSE; + + cairo_translate (xrs, -x_off, -y_off); view->board_pad_x = (widget->allocation.width - view->board_width * view->cell_width) / 2; view->board_pad_y = (widget->allocation.height - view->board_height * view->cell_height) / 2; - XrTranslate (xrs, view->board_pad_x, view->board_pad_y); + cairo_translate (xrs, view->board_pad_x, view->board_pad_y); goal_target = rr_board_get_goal_target (board); - /* Draw cell targets */ + /* Draw cell contents */ for (j=0; j < view->board_height; j++) { for (i=0; i < view->board_width; i++) { - XrSave (xrs); - XrTranslate (xrs, i * view->cell_width, j * view->cell_height); - grr_board_view_draw_cell (view, xrs, - rr_board_get_cell (board, i, j), - goal_target, - view->cell_width, view->cell_height); - XrRestore (xrs); + if (! view->damaged[j][i]) + continue; + rr_cell_t cell = rr_board_get_cell (board, i, j); + rr_target_t target = RR_CELL_GET_TARGET (cell); + rr_robot_t robot = RR_CELL_GET_ROBOT (cell); + + cairo_save (xrs); + cairo_translate (xrs, i * view->cell_width, j * view->cell_height); + + grr_icon_draw_predrawn (view->cell_icon, xrs); + + if (target) { + if (target && target != goal_target) { + cairo_save (xrs); + cairo_set_alpha (xrs, 0.25); + grr_icon_draw_predrawn (view->target_icon[rr_target_idx (target)], xrs); + cairo_restore (xrs); + } else { + grr_icon_draw_predrawn (view->target_icon[rr_target_idx (target)], xrs); + } + } + + if (robot) + grr_icon_draw_predrawn (view->robot_icon[rr_robot_idx (robot)], xrs); + + cairo_restore (xrs); } } /* Draw goal target in center of board */ /* XXX: Not a perfect heuristic. Should check for the vacant box too. */ if (view->board_width == 16 && view->board_height == 16) { - XrSave (xrs); - XrTranslate (xrs, + cairo_save (xrs); + cairo_translate (xrs, (view->board_width / 2 - 1) * view->cell_width, (view->board_height / 2 - 1) * view->cell_height); - grr_board_view_draw_cell (view, xrs, goal_target, goal_target, - view->cell_width * 2, view->cell_height * 2); - XrRestore (xrs); + cairo_scale (xrs, + 2 * view->cell_width / GRR_SVG_ASSUMED_WIDTH, + 2 * view->cell_height / GRR_SVG_ASSUMED_HEIGHT); + grr_icon_draw (view->target_icon[rr_target_idx (goal_target)], xrs); + cairo_restore (xrs); } /* Draw walls */ for (j=0; j < view->board_height; j++) { for (i=0; i < view->board_width; i++) { - XrSave (xrs); - XrTranslate (xrs, i * view->cell_width, j * view->cell_height); - XrScale (xrs, + if (! view->damaged[j][i]) + continue; + view->damaged[j][i] = 0; + cairo_save (xrs); + cairo_translate (xrs, i * view->cell_width, j * view->cell_height); + cairo_scale (xrs, view->cell_width / GRR_SVG_ASSUMED_WIDTH, view->cell_height / GRR_SVG_ASSUMED_HEIGHT); grr_board_view_draw_walls (view, xrs, RR_CELL_GET_WALLS (rr_board_get_cell(board, i, j))); - XrRestore (xrs); + cairo_restore (xrs); } } - XrDestroy (xrs); + cairo_destroy (xrs); return FALSE; } -static void -grr_board_view_pointer_coords_to_grid (grr_board_view_t *view, - int pointer_x, int pointer_y, - int *grid_x, int *grid_y) +void +grr_board_view_transform_pixel_to_cell (grr_board_view_t *view, + int pixel_x, int pixel_y, + int *cell_x, int *cell_y) { - *grid_x = (pointer_x - view->board_pad_x) / view->cell_width; - *grid_y = (pointer_y - view->board_pad_y) / view->cell_height; + int x, y; + x = (pixel_x - view->board_pad_x) / view->cell_width; + y = (pixel_y - view->board_pad_y) / view->cell_height; + if (x < 0) + x = 0; + if (x >= view->board_width) + x = view->board_width - 1; + if (y < 0) + y = 0; + if (y >= view->board_height) + y = view->board_height - 1; + *cell_x = x; + *cell_y = y; +} + +void +grr_board_view_transform_cell_to_pixel (grr_board_view_t *view, + int cell_x, int cell_y, + int *pixel_x, int *pixel_y) +{ + *pixel_x = view->cell_width * cell_x + view->board_pad_x; + *pixel_y = view->cell_height * cell_y + view->board_pad_y; } static gint @@ -540,9 +538,9 @@ grr_board_view_button_press (GtkWidget *widget, view = GRR_BOARD_VIEW (widget); - grr_board_view_pointer_coords_to_grid (view, - event->x, event->y, - &x, &y); + grr_board_view_transform_pixel_to_cell (view, + event->x, event->y, + &x, &y); cell = rr_board_get_cell (view->board, x, y); if (!view->button && RR_CELL_GET_ROBOT (cell)) { @@ -579,7 +577,7 @@ grr_board_view_button_release (GtkWidget *widget, view->button = 0; } - grr_board_view_pointer_coords_to_grid (view, event->x, event->y, &x, &y); + grr_board_view_transform_pixel_to_cell (view, event->x, event->y, &x, &y); rr_board_find_robot (view->board, view->active_robot, &robot_x, &robot_y); dx = x - robot_x; @@ -655,12 +653,11 @@ grr_board_view_update_mouse (grr_board_view_t *view, gint x, gint y) /* XXX: Perhaps should draw a robot here */ } -static void -grr_board_view_update (grr_board_view_t *view) +void +grr_board_view_mark_damage (grr_board_view_t *view, int i, int j) { - g_return_if_fail (view != NULL); - g_return_if_fail (GRR_IS_BOARD_VIEW (view)); + int x, y; - gtk_widget_queue_draw (GTK_WIDGET (view)); + grr_board_view_transform_cell_to_pixel (view, i, j, &x, &y); + gtk_widget_queue_draw_area (GTK_WIDGET (view), x, y, view->cell_width, view->cell_height); } -