]> git.cworth.org Git - grrobot/blobdiff - src/grr_board_view.c
Fixed select handling. Added two of Richard's fancy logos.
[grrobot] / src / grr_board_view.c
index b48c2913e8a9cef451cc4311719d4a433b1789d8..a03a708e9a152b01231ca785993bb03a7fc9bf57 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <Xr.h>
+#include <cairo.h>
 #include <xsvg.h>
 
 #include <gtk/gtkmain.h>
@@ -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);
 }
-