/* * update_cursor: * @area: a #UmCropArea * @x: x coordinate * @y: y coordinate * * Update the type of the cursor, depending on which point of the crop * rectangle the pointer is over. */ static void update_cursor (UmCropArea *area, gint x, gint y) { UmCropAreaPrivate *priv = um_crop_area_get_instance_private (area); gint cursor_type; GdkRectangle crop; gint region; region = priv->active_region; if (region == OUTSIDE) { crop_to_widget (area, &crop); region = find_location (&crop, x, y); } switch (region) { case OUTSIDE: cursor_type = GDK_LEFT_PTR; break; case TOP_LEFT: cursor_type = GDK_TOP_LEFT_CORNER; break; case TOP: cursor_type = GDK_TOP_SIDE; break; case TOP_RIGHT: cursor_type = GDK_TOP_RIGHT_CORNER; break; case LEFT: cursor_type = GDK_LEFT_SIDE; break; case INSIDE: cursor_type = GDK_FLEUR; break; case RIGHT: cursor_type = GDK_RIGHT_SIDE; break; case BOTTOM_LEFT: cursor_type = GDK_BOTTOM_LEFT_CORNER; break; case BOTTOM: cursor_type = GDK_BOTTOM_SIDE; break; case BOTTOM_RIGHT: cursor_type = GDK_BOTTOM_RIGHT_CORNER; break; default: g_assert_not_reached (); } if (cursor_type != priv->current_cursor) { GdkCursor *cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (area)), cursor_type); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (area)), cursor); g_object_unref (cursor); priv->current_cursor = cursor_type; } }
static gboolean um_crop_area_button_release_event (GtkWidget *widget, GdkEventButton *event) { UmCropArea *area = UM_CROP_AREA (widget); GdkRectangle crop; if (area->priv->browse_pixbuf == NULL) return FALSE; crop_to_widget (area, &crop); area->priv->last_press_x = -1; area->priv->last_press_y = -1; area->priv->active_region = OUTSIDE; gtk_widget_queue_draw_area (widget, crop.x - 1, crop.y - 1, crop.width + 2, crop.height + 2); return FALSE; }
static gboolean um_crop_area_button_press_event (GtkWidget *widget, GdkEventButton *event) { UmCropArea *area = UM_CROP_AREA (widget); GdkRectangle crop; if (area->priv->browse_pixbuf == NULL) return FALSE; crop_to_widget (area, &crop); area->priv->last_press_x = (event->x - area->priv->image.x) / area->priv->scale; area->priv->last_press_y = (event->y - area->priv->image.y) / area->priv->scale; area->priv->active_region = find_location (&crop, event->x, event->y); gtk_widget_queue_draw_area (widget, crop.x - 1, crop.y - 1, crop.width + 2, crop.height + 2); return FALSE; }
static gboolean um_crop_area_motion_notify_event (GtkWidget *widget, GdkEventMotion *event) { UmCropArea *area = UM_CROP_AREA (widget); gint x, y; gint delta_x, delta_y; gint width, height; gint adj_width, adj_height; gint pb_width, pb_height; GdkRectangle damage; gint left, right, top, bottom; gdouble new_width, new_height; gdouble center_x, center_y; gint min_width, min_height; if (area->priv->browse_pixbuf == NULL) return FALSE; update_cursor (area, event->x, event->y); crop_to_widget (area, &damage); gtk_widget_queue_draw_area (widget, damage.x - 1, damage.y - 1, damage.width + 2, damage.height + 2); pb_width = gdk_pixbuf_get_width (area->priv->browse_pixbuf); pb_height = gdk_pixbuf_get_height (area->priv->browse_pixbuf); x = (event->x - area->priv->image.x) / area->priv->scale; y = (event->y - area->priv->image.y) / area->priv->scale; delta_x = x - area->priv->last_press_x; delta_y = y - area->priv->last_press_y; area->priv->last_press_x = x; area->priv->last_press_y = y; left = area->priv->crop.x; right = area->priv->crop.x + area->priv->crop.width - 1; top = area->priv->crop.y; bottom = area->priv->crop.y + area->priv->crop.height - 1; center_x = (left + right) / 2.0; center_y = (top + bottom) / 2.0; switch (area->priv->active_region) { case INSIDE: width = right - left + 1; height = bottom - top + 1; left += delta_x; right += delta_x; top += delta_y; bottom += delta_y; if (left < 0) left = 0; if (top < 0) top = 0; if (right > pb_width) right = pb_width; if (bottom > pb_height) bottom = pb_height; adj_width = right - left + 1; adj_height = bottom - top + 1; if (adj_width != width) { if (delta_x < 0) right = left + width - 1; else left = right - width + 1; } if (adj_height != height) { if (delta_y < 0) bottom = top + height - 1; else top = bottom - height + 1; } break; case TOP_LEFT: if (area->priv->aspect < 0) { top = y; left = x; } else if (y < eval_radial_line (center_x, center_y, left, top, x)) { top = y; new_width = (bottom - top) * area->priv->aspect; left = right - new_width; } else { left = x; new_height = (right - left) / area->priv->aspect; top = bottom - new_height; } break; case TOP: top = y; if (area->priv->aspect > 0) { new_width = (bottom - top) * area->priv->aspect; right = left + new_width; } break; case TOP_RIGHT: if (area->priv->aspect < 0) { top = y; right = x; } else if (y < eval_radial_line (center_x, center_y, right, top, x)) { top = y; new_width = (bottom - top) * area->priv->aspect; right = left + new_width; } else { right = x; new_height = (right - left) / area->priv->aspect; top = bottom - new_height; } break; case LEFT: left = x; if (area->priv->aspect > 0) { new_height = (right - left) / area->priv->aspect; bottom = top + new_height; } break; case BOTTOM_LEFT: if (area->priv->aspect < 0) { bottom = y; left = x; } else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) { left = x; new_height = (right - left) / area->priv->aspect; bottom = top + new_height; } else { bottom = y; new_width = (bottom - top) * area->priv->aspect; left = right - new_width; } break; case RIGHT: right = x; if (area->priv->aspect > 0) { new_height = (right - left) / area->priv->aspect; bottom = top + new_height; } break; case BOTTOM_RIGHT: if (area->priv->aspect < 0) { bottom = y; right = x; } else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) { right = x; new_height = (right - left) / area->priv->aspect; bottom = top + new_height; } else { bottom = y; new_width = (bottom - top) * area->priv->aspect; right = left + new_width; } break; case BOTTOM: bottom = y; if (area->priv->aspect > 0) { new_width = (bottom - top) * area->priv->aspect; right= left + new_width; } break; default: return FALSE; } min_width = area->priv->base_width / area->priv->scale; min_height = area->priv->base_height / area->priv->scale; width = right - left + 1; height = bottom - top + 1; if (area->priv->aspect < 0) { if (left < 0) left = 0; if (top < 0) top = 0; if (right > pb_width) right = pb_width; if (bottom > pb_height) bottom = pb_height; width = right - left + 1; height = bottom - top + 1; switch (area->priv->active_region) { case LEFT: case TOP_LEFT: case BOTTOM_LEFT: if (width < min_width) left = right - min_width; break; case RIGHT: case TOP_RIGHT: case BOTTOM_RIGHT: if (width < min_width) right = left + min_width; break; default: ; } switch (area->priv->active_region) { case TOP: case TOP_LEFT: case TOP_RIGHT: if (height < min_height) top = bottom - min_height; break; case BOTTOM: case BOTTOM_LEFT: case BOTTOM_RIGHT: if (height < min_height) bottom = top + min_height; break; default: ; } } else { if (left < 0 || top < 0 || right > pb_width || bottom > pb_height || width < min_width || height < min_height) { left = area->priv->crop.x; right = area->priv->crop.x + area->priv->crop.width - 1; top = area->priv->crop.y; bottom = area->priv->crop.y + area->priv->crop.height - 1; } } area->priv->crop.x = left; area->priv->crop.y = top; area->priv->crop.width = right - left + 1; area->priv->crop.height = bottom - top + 1; crop_to_widget (area, &damage); gtk_widget_queue_draw_area (widget, damage.x - 1, damage.y - 1, damage.width + 2, damage.height + 2); return FALSE; }
static gboolean um_crop_area_draw (GtkWidget *widget, cairo_t *cr) { GdkRectangle crop; gint width, height; UmCropArea *uarea = UM_CROP_AREA (widget); if (uarea->priv->browse_pixbuf == NULL) return FALSE; update_pixbufs (uarea); width = gdk_pixbuf_get_width (uarea->priv->pixbuf); height = gdk_pixbuf_get_height (uarea->priv->pixbuf); crop_to_widget (uarea, &crop); gdk_cairo_set_source_pixbuf (cr, uarea->priv->color_shifted, 0, 0); cairo_rectangle (cr, 0, 0, width, crop.y); cairo_rectangle (cr, 0, crop.y, crop.x, crop.height); cairo_rectangle (cr, crop.x + crop.width, crop.y, width - crop.x - crop.width, crop.height); cairo_rectangle (cr, 0, crop.y + crop.height, width, height - crop.y - crop.height); cairo_fill (cr); gdk_cairo_set_source_pixbuf (cr, uarea->priv->pixbuf, 0, 0); cairo_rectangle (cr, crop.x, crop.y, crop.width, crop.height); cairo_fill (cr); if (uarea->priv->active_region != OUTSIDE) { gint x1, x2, y1, y2; cairo_set_source_rgb (cr, 1, 1, 1); cairo_set_line_width (cr, 1.0); x1 = crop.x + crop.width / 3.0; x2 = crop.x + 2 * crop.width / 3.0; y1 = crop.y + crop.height / 3.0; y2 = crop.y + 2 * crop.height / 3.0; cairo_move_to (cr, x1 + 0.5, crop.y); cairo_line_to (cr, x1 + 0.5, crop.y + crop.height); cairo_move_to (cr, x2 + 0.5, crop.y); cairo_line_to (cr, x2 + 0.5, crop.y + crop.height); cairo_move_to (cr, crop.x, y1 + 0.5); cairo_line_to (cr, crop.x + crop.width, y1 + 0.5); cairo_move_to (cr, crop.x, y2 + 0.5); cairo_line_to (cr, crop.x + crop.width, y2 + 0.5); cairo_stroke (cr); } cairo_set_source_rgb (cr, 0, 0, 0); cairo_set_line_width (cr, 1.0); cairo_rectangle (cr, crop.x + 0.5, crop.y + 0.5, crop.width - 1.0, crop.height - 1.0); cairo_stroke (cr); cairo_set_source_rgb (cr, 1, 1, 1); cairo_set_line_width (cr, 2.0); cairo_rectangle (cr, crop.x + 2.0, crop.y + 2.0, crop.width - 4.0, crop.height - 4.0); cairo_stroke (cr); return FALSE; }
static gboolean um_crop_area_expose (GtkWidget *widget, GdkEventExpose *event) { cairo_t *cr; GdkRectangle area; GdkRectangle crop; gint width, height; UmCropArea *uarea = UM_CROP_AREA (widget); if (uarea->priv->browse_pixbuf == NULL) return FALSE; update_pixbufs (uarea); width = gdk_pixbuf_get_width (uarea->priv->pixbuf); height = gdk_pixbuf_get_height (uarea->priv->pixbuf); crop_to_widget (uarea, &crop); area.x = 0; area.y = 0; area.width = width; area.height = crop.y; gdk_rectangle_intersect (&area, &event->area, &area); gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], uarea->priv->color_shifted, area.x, area.y, area.x, area.y, area.width, area.height, GDK_RGB_DITHER_NONE, 0, 0); area.x = 0; area.y = crop.y; area.width = crop.x; area.height = crop.height; gdk_rectangle_intersect (&area, &event->area, &area); gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], uarea->priv->color_shifted, area.x, area.y, area.x, area.y, area.width, area.height, GDK_RGB_DITHER_NONE, 0, 0); area.x = crop.x; area.y = crop.y; area.width = crop.width; area.height = crop.height; gdk_rectangle_intersect (&area, &event->area, &area); gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], uarea->priv->pixbuf, area.x, area.y, area.x, area.y, area.width, area.height, GDK_RGB_DITHER_NONE, 0, 0); area.x = crop.x + crop.width; area.y = crop.y; area.width = width - area.x; area.height = crop.height; gdk_rectangle_intersect (&area, &event->area, &area); gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], uarea->priv->color_shifted, area.x, area.y, area.x, area.y, area.width, area.height, GDK_RGB_DITHER_NONE, 0, 0); area.x = 0; area.y = crop.y + crop.height; area.width = width; area.height = height - area.y; gdk_rectangle_intersect (&area, &event->area, &area); gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], uarea->priv->color_shifted, area.x, area.y, area.x, area.y, area.width, area.height, GDK_RGB_DITHER_NONE, 0, 0); cr = gdk_cairo_create (widget->window); gdk_cairo_rectangle (cr, &event->area); cairo_clip (cr); if (uarea->priv->active_region != OUTSIDE) { gint x1, x2, y1, y2; gdk_cairo_set_source_color (cr, &widget->style->white); cairo_set_line_width (cr, 1.0); x1 = crop.x + crop.width / 3.0; x2 = crop.x + 2 * crop.width / 3.0; y1 = crop.y + crop.height / 3.0; y2 = crop.y + 2 * crop.height / 3.0; cairo_move_to (cr, x1 + 0.5, crop.y); cairo_line_to (cr, x1 + 0.5, crop.y + crop.height); cairo_move_to (cr, x2 + 0.5, crop.y); cairo_line_to (cr, x2 + 0.5, crop.y + crop.height); cairo_move_to (cr, crop.x, y1 + 0.5); cairo_line_to (cr, crop.x + crop.width, y1 + 0.5); cairo_move_to (cr, crop.x, y2 + 0.5); cairo_line_to (cr, crop.x + crop.width, y2 + 0.5); cairo_stroke (cr); } gdk_cairo_set_source_color (cr, &widget->style->black); cairo_set_line_width (cr, 1.0); cairo_rectangle (cr, crop.x + 0.5, crop.y + 0.5, crop.width - 1.0, crop.height - 1.0); cairo_stroke (cr); gdk_cairo_set_source_color (cr, &widget->style->white); cairo_set_line_width (cr, 2.0); cairo_rectangle (cr, crop.x + 2.0, crop.y + 2.0, crop.width - 4.0, crop.height - 4.0); cairo_stroke (cr); cairo_destroy (cr); return FALSE; }