mirror of
https://gitlab.gnome.org/GNOME/eog
synced 2024-10-19 14:34:42 +00:00
New function to do proper scrolling of the image view. (drag_to): Use
2000-04-21 Federico Mena Quintero <federico@helixcode.com> * image-view.c (scroll_to): New function to do proper scrolling of the image view. (drag_to): Use scroll_to(). (adjustment_changed_cb): Use scroll_to(). * uta.c (uta_copy_area): New function to do the equivalent of a BitBlt on a microtile array. It is not perfect; see the FIXME for details. (copy_tile): Helper function for uta_copy_area(). (uta_ensure_size): Create a new uta with the proper size if the specified uta is NULL. (uta_add_rect): Special-case source tiles that are empty so as not to add a bigger region than needed.
This commit is contained in:
parent
59fbfdcf67
commit
5585c9d681
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtksignal.h>
|
||||
#include "cursors.h"
|
||||
#include "image-view.h"
|
||||
|
@ -57,6 +58,9 @@ typedef struct {
|
|||
GtkAdjustment *hadj;
|
||||
GtkAdjustment *vadj;
|
||||
|
||||
/* Current scrolling offsets */
|
||||
int xofs, yofs;
|
||||
|
||||
/* Microtile array for dirty region */
|
||||
ArtUta *uta;
|
||||
|
||||
|
@ -324,12 +328,12 @@ paint_rectangle (ImageView *view, ArtIRect *rect)
|
|||
if (scaled_width < width)
|
||||
xofs = (width - scaled_width) / 2;
|
||||
else
|
||||
xofs = -priv->hadj->value;
|
||||
xofs = -priv->xofs;
|
||||
|
||||
if (scaled_height < height)
|
||||
yofs = (height - scaled_height) / 2;
|
||||
else
|
||||
yofs = -priv->vadj->value;
|
||||
yofs = -priv->yofs;
|
||||
|
||||
/* Draw background if necessary, in four steps */
|
||||
|
||||
|
@ -412,6 +416,17 @@ paint_rectangle (ImageView *view, ArtIRect *rect)
|
|||
d.x0 - xofs, d.y0 - yofs);
|
||||
|
||||
gdk_pixbuf_unref (tmp);
|
||||
|
||||
#if 0
|
||||
gdk_draw_line (GTK_WIDGET (view)->window,
|
||||
GTK_WIDGET (view)->style->black_gc,
|
||||
d.x0, d.y0,
|
||||
d.x1 - 1, d.y1 - 1);
|
||||
gdk_draw_line (GTK_WIDGET (view)->window,
|
||||
GTK_WIDGET (view)->style->black_gc,
|
||||
d.x1 - 1, d.y0,
|
||||
d.x0, d.y1 - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Idle handler for the drawing process. We pull a rectangle from the dirty
|
||||
|
@ -480,6 +495,119 @@ request_paint_area (ImageView *view, GdkRectangle *area)
|
|||
}
|
||||
}
|
||||
|
||||
/* Scrolls the view to the specified offsets. Does not perform range checking! */
|
||||
static void
|
||||
scroll_to (ImageView *view, int x, int y)
|
||||
{
|
||||
ImageViewPrivate *priv;
|
||||
int xofs, yofs;
|
||||
GdkWindow *window;
|
||||
GdkGC *gc;
|
||||
int width, height;
|
||||
int src_x, src_y;
|
||||
int dest_x, dest_y;
|
||||
int twidth, theight;
|
||||
GdkEvent *event;
|
||||
|
||||
priv = view->priv;
|
||||
|
||||
/* Compute offsets and check bounds */
|
||||
|
||||
xofs = x - priv->xofs;
|
||||
yofs = y - priv->yofs;
|
||||
|
||||
if (xofs == 0 && yofs == 0)
|
||||
return;
|
||||
|
||||
width = GTK_WIDGET (view)->allocation.width;
|
||||
height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
priv->xofs = x;
|
||||
priv->yofs = y;
|
||||
|
||||
if (abs (xofs) >= width || abs (yofs) >= height) {
|
||||
GdkRectangle area;
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = width;
|
||||
area.height = height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
return;
|
||||
}
|
||||
|
||||
window = GTK_WIDGET (view)->window;
|
||||
|
||||
/* Ensure that the uta has the full size */
|
||||
|
||||
twidth = (width + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
theight = (height + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
|
||||
if (priv->uta)
|
||||
g_assert (priv->idle_id != 0);
|
||||
else
|
||||
priv->idle_id = g_idle_add (paint_iteration_idle, view);
|
||||
|
||||
priv->uta = uta_ensure_size (priv->uta, 0, 0, twidth, theight);
|
||||
|
||||
/* Copy the uta area and add the scrolled-in region */
|
||||
|
||||
src_x = xofs < 0 ? 0 : xofs;
|
||||
src_y = yofs < 0 ? 0 : yofs;
|
||||
dest_x = xofs < 0 ? -xofs : 0;
|
||||
dest_y = yofs < 0 ? -yofs : 0;
|
||||
|
||||
uta_copy_area (priv->uta,
|
||||
src_x, src_y,
|
||||
dest_x, dest_y,
|
||||
width - abs (xofs), height - abs (yofs));
|
||||
|
||||
if (xofs) {
|
||||
int xx;
|
||||
|
||||
xx = xofs < 0 ? 0 : width - xofs;
|
||||
uta_add_rect (priv->uta,
|
||||
xx, 0,
|
||||
xx + abs (xofs), height);
|
||||
}
|
||||
|
||||
if (yofs) {
|
||||
int yy;
|
||||
|
||||
yy = yofs < 0 ? 0 : height - yofs;
|
||||
uta_add_rect (priv->uta,
|
||||
0, yy,
|
||||
width, yy + abs (yofs));
|
||||
}
|
||||
|
||||
/* Copy the window area */
|
||||
|
||||
gc = gdk_gc_new (window);
|
||||
gdk_gc_set_exposures (gc, TRUE);
|
||||
|
||||
gdk_window_copy_area (window,
|
||||
gc,
|
||||
dest_x, dest_y,
|
||||
window,
|
||||
src_x, src_y,
|
||||
width - abs (xofs),
|
||||
height - abs (yofs));
|
||||
|
||||
gdk_gc_destroy (gc);
|
||||
|
||||
/* Process graphics exposures */
|
||||
|
||||
while ((event = gdk_event_get_graphics_expose (window)) != NULL) {
|
||||
gtk_widget_event (GTK_WIDGET (view), event);
|
||||
if (event->expose.count == 0) {
|
||||
gdk_event_free (event);
|
||||
break;
|
||||
}
|
||||
gdk_event_free (event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Widget methods */
|
||||
|
@ -668,8 +796,8 @@ image_view_button_press (GtkWidget *widget, GdkEventButton *event)
|
|||
priv->drag_anchor_x = event->x;
|
||||
priv->drag_anchor_y = event->y;
|
||||
|
||||
priv->drag_ofs_x = priv->hadj->value;
|
||||
priv->drag_ofs_y = priv->vadj->value;
|
||||
priv->drag_ofs_x = priv->xofs;
|
||||
priv->drag_ofs_y = priv->yofs;
|
||||
|
||||
cursor = cursor_get (widget->window, CURSOR_HAND_CLOSED);
|
||||
gdk_pointer_grab (widget->window,
|
||||
|
@ -691,7 +819,6 @@ drag_to (ImageView *view, int x, int y)
|
|||
{
|
||||
ImageViewPrivate *priv;
|
||||
int dx, dy;
|
||||
GdkRectangle area;
|
||||
|
||||
priv = view->priv;
|
||||
|
||||
|
@ -701,6 +828,8 @@ drag_to (ImageView *view, int x, int y)
|
|||
x = CLAMP (priv->drag_ofs_x + dx, 0, priv->hadj->upper - priv->hadj->page_size);
|
||||
y = CLAMP (priv->drag_ofs_y + dy, 0, priv->vadj->upper - priv->vadj->page_size);
|
||||
|
||||
scroll_to (view, x, y);
|
||||
|
||||
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->hadj), view);
|
||||
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->vadj), view);
|
||||
|
||||
|
@ -712,15 +841,6 @@ drag_to (ImageView *view, int x, int y)
|
|||
|
||||
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->hadj), view);
|
||||
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->vadj), view);
|
||||
|
||||
/* FIXME: use copy_area() for the window and the uta */
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = GTK_WIDGET (view)->allocation.width;
|
||||
area.height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
}
|
||||
|
||||
/* Button release handler for the image view */
|
||||
|
@ -791,19 +911,11 @@ adjustment_changed_cb (GtkAdjustment *adj, gpointer data)
|
|||
{
|
||||
ImageView *view;
|
||||
ImageViewPrivate *priv;
|
||||
GdkRectangle area;
|
||||
|
||||
view = IMAGE_VIEW (data);
|
||||
priv = view->priv;
|
||||
|
||||
/* FIXME: use copy_area() for the window and the uta */
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = GTK_WIDGET (view)->allocation.width;
|
||||
area.height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
scroll_to (view, priv->hadj->value, priv->vadj->value);
|
||||
}
|
||||
|
||||
/* Set_scroll_adjustments handler for the image view */
|
||||
|
|
495
libeog/uta.c
495
libeog/uta.c
|
@ -33,7 +33,7 @@
|
|||
* @y1: Top microtile coordinate that must fit in new array.
|
||||
* @x2: Right microtile coordinate that must fit in new array.
|
||||
* @y2: Bottom microtile coordinate that must fit in new array.
|
||||
*
|
||||
*
|
||||
* Ensures that the size of a microtile array is big enough to fit the specified
|
||||
* microtile coordinates. If it is not big enough, the specified @uta will be
|
||||
* freed and a new one will be returned. Otherwise, the original @uta will be
|
||||
|
@ -42,7 +42,7 @@
|
|||
*
|
||||
* Note that the specified coordinates must have already been scaled down by the
|
||||
* ART_UTILE_SHIFT factor.
|
||||
*
|
||||
*
|
||||
* Return value: The same value as @uta if the original microtile array was
|
||||
* big enough to fit the specified microtile coordinates, or a new array if
|
||||
* it needed to be grown. In the second case, the original @uta will be
|
||||
|
@ -56,10 +56,12 @@ uta_ensure_size (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
int new_ofs, ofs;
|
||||
int x, y;
|
||||
|
||||
g_return_val_if_fail (uta != NULL, NULL);
|
||||
g_return_val_if_fail (x1 < x2, NULL);
|
||||
g_return_val_if_fail (y1 < y2, NULL);
|
||||
|
||||
if (!uta)
|
||||
return art_uta_new (x1, y1, x2, y2);
|
||||
|
||||
if (x1 >= uta->x0
|
||||
&& y1 >= uta->y0
|
||||
&& x2 <= uta->x0 + uta->width
|
||||
|
@ -105,10 +107,10 @@ uta_ensure_size (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
* @y1: Top coordinate of rectangle.
|
||||
* @x2: Right coordinate of rectangle.
|
||||
* @y2: Bottom coordinate of rectangle.
|
||||
*
|
||||
*
|
||||
* Adds the specified rectangle to a microtile array. The array is
|
||||
* grown to fit the rectangle if necessary.
|
||||
*
|
||||
*
|
||||
* Return value: The original @uta, or a new microtile array if the original one
|
||||
* needed to be grown to fit the specified rectangle. In the second case, the
|
||||
* original @uta will be freed automatically.
|
||||
|
@ -162,83 +164,133 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
if (rect_y2 - rect_y1 == 1) {
|
||||
if (rect_x2 - rect_x1 == 1) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
} else {
|
||||
/* Leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
|
||||
/* Tiles in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
|
||||
/* Rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
} else {
|
||||
if (rect_x2 - rect_x1 == 1) {
|
||||
/* Topmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
ofs += uta->width;
|
||||
|
||||
/* Tiles in between */
|
||||
for (y = rect_y1 + 1; y < rect_y2 - 1; y++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
ofs += uta->width;
|
||||
}
|
||||
|
||||
/* Bottommost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
} else {
|
||||
/* Top row, leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
/* Top row, in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
/* Top row, rightmost tile */
|
||||
/* Top row, rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
ofs += uta->width - (rect_x2 - rect_x1 - 1);
|
||||
|
||||
|
@ -246,10 +298,15 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
for (y = rect_y1 + 1; y < rect_y2 - 1; y++) {
|
||||
/* Leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
/* Tiles in between */
|
||||
bb = ART_UTA_BBOX_CONS (0, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
|
@ -258,36 +315,56 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
|
||||
/* Rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
ofs += uta->width - (rect_x2 - rect_x1 - 1);
|
||||
}
|
||||
|
||||
/* Bottom row, leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
|
||||
/* Bottom row, tiles in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, 0, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
|
||||
/* Bottom row, rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,7 +378,7 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
* @y1: Top coordinate of rectangle.
|
||||
* @x2: Right coordinate of rectangle.
|
||||
* @y2: Bottom coordinate of rectangle.
|
||||
*
|
||||
*
|
||||
* Removes a rectangular region from the specified microtile array. Due to the
|
||||
* way microtile arrays represent regions, the tiles at the edge of the
|
||||
* rectangle may not be clipped exactly.
|
||||
|
@ -363,7 +440,7 @@ uta_remove_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
ArtUtaBbox bb;
|
||||
int bb_x1, bb_y1, bb_x2, bb_y2;
|
||||
int bb_cx1, bb_cy1, bb_cx2, bb_cy2;
|
||||
|
||||
|
||||
bb = utiles[ofs];
|
||||
bb_x1 = ART_UTA_BBOX_X0 (bb);
|
||||
bb_y1 = ART_UTA_BBOX_Y0 (bb);
|
||||
|
@ -588,3 +665,285 @@ uta_find_first_glom_rect (ArtUta *uta, ArtIRect *rect, int max_width, int max_he
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Copies a single microtile to another location in the UTA, offsetted by the
|
||||
* specified distance. A microtile can thus end up being added in a single part
|
||||
* to another microtile, in two parts to two horizontally or vertically adjacent
|
||||
* microtiles, or in four parts to a 2x2 square of microtiles.
|
||||
*
|
||||
* This is basically a normal BitBlt but with copying-forwards-to-the-destination
|
||||
* instead of fetching-backwards-from-the-source.
|
||||
*/
|
||||
static void
|
||||
copy_tile (ArtUta *uta, int x, int y, int xofs, int yofs)
|
||||
{
|
||||
ArtUtaBbox *utiles;
|
||||
ArtUtaBbox bb, dbb;
|
||||
int t_x1, t_y1, t_x2, t_y2;
|
||||
int d_x1, d_y1, d_x2, d_y2;
|
||||
int d_tx1, d_ty1;
|
||||
int d_xf1, d_yf1, d_xf2, d_yf2;
|
||||
int dofs;
|
||||
|
||||
utiles = uta->utiles;
|
||||
|
||||
bb = utiles[(y - uta->y0) * uta->width + x - uta->x0];
|
||||
|
||||
if (bb == 0)
|
||||
return;
|
||||
|
||||
t_x1 = ART_UTA_BBOX_X0 (bb) + (x << ART_UTILE_SHIFT);
|
||||
t_y1 = ART_UTA_BBOX_Y0 (bb) + (y << ART_UTILE_SHIFT);
|
||||
t_x2 = ART_UTA_BBOX_X1 (bb) + (x << ART_UTILE_SHIFT);
|
||||
t_y2 = ART_UTA_BBOX_Y1 (bb) + (y << ART_UTILE_SHIFT);
|
||||
|
||||
d_x1 = t_x1 + xofs;
|
||||
d_y1 = t_y1 + yofs;
|
||||
d_x2 = t_x2 + xofs;
|
||||
d_y2 = t_y2 + yofs;
|
||||
|
||||
d_tx1 = d_x1 >> ART_UTILE_SHIFT;
|
||||
d_ty1 = d_y1 >> ART_UTILE_SHIFT;
|
||||
|
||||
dofs = (d_ty1 - uta->y0) * uta->width + d_tx1 - uta->x0;
|
||||
|
||||
d_xf1 = d_x1 & (ART_UTILE_SIZE - 1);
|
||||
d_yf1 = d_y1 & (ART_UTILE_SIZE - 1);
|
||||
d_xf2 = ((d_x2 - 1) & (ART_UTILE_SIZE - 1)) + 1;
|
||||
d_yf2 = ((d_y2 - 1) & (ART_UTILE_SIZE - 1)) + 1;
|
||||
|
||||
if (d_x2 - d_x1 <= ART_UTILE_SIZE - d_xf1) {
|
||||
if (d_y2 - d_y1 <= ART_UTILE_SIZE - d_yf1) {
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
} else {
|
||||
/* Top tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, d_xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs += uta->width;
|
||||
|
||||
/* Bottom tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, 0, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (d_y2 - d_y1 <= ART_UTILE_SIZE - d_yf1) {
|
||||
/* Left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, ART_UTILE_SIZE, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, d_yf1, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
} else {
|
||||
/* Top left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Top right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, d_yf1, d_xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs += uta->width - 1;
|
||||
|
||||
/* Bottom left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, 0, ART_UTILE_SIZE, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Bottom right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uta_copy_area:
|
||||
* @uta: A microtile array.
|
||||
* @src_x: Left coordinate of source rectangle.
|
||||
* @src_y: Top coordinate of source rectangle.
|
||||
* @dest_x: Left coordinate of destination.
|
||||
* @dest_y: Top coordinate of destination.
|
||||
* @width: Width of region to copy.
|
||||
* @height: Height of region to copy.
|
||||
*
|
||||
* Copies a rectangular region within a microtile array. The array will not be
|
||||
* expanded if the destination area does not fit within it; rather only the area
|
||||
* that fits will be copied. The source rectangle must be completely contained
|
||||
* within the microtile array.
|
||||
**/
|
||||
void
|
||||
uta_copy_area (ArtUta *uta, int src_x, int src_y, int dest_x, int dest_y, int width, int height)
|
||||
{
|
||||
ArtUtaBbox *utiles;
|
||||
int rect_x1, rect_y1, rect_x2, rect_y2;
|
||||
gboolean top_to_bottom, left_to_right;
|
||||
int xofs, yofs;
|
||||
int x, y;
|
||||
|
||||
g_return_if_fail (uta != NULL);
|
||||
g_return_if_fail (width >= 0 && height >= 0);
|
||||
g_return_if_fail (src_x >= uta->x0 << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_y >= uta->y0 << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_x + width <= (uta->x0 + uta->width) << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_y + height <= (uta->y0 + uta->height) << ART_UTILE_SHIFT);
|
||||
|
||||
if ((src_x == dest_x && src_y == dest_y) || width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
/* FIXME: This function is not perfect. It *adds* the copied/offsetted
|
||||
* area to the original contents of the microtile array, thus growing
|
||||
* the region more than needed. The effect should be to "overwrite" the
|
||||
* original contents, just like XCopyArea() does. Care needs to be
|
||||
* taken when the edges of the rectangle do not fall on microtile
|
||||
* boundaries, because tiles may need to be "split".
|
||||
*
|
||||
* Maybe this will work:
|
||||
*
|
||||
* 1. Copy the rectangular array of tiles that form the region to a
|
||||
* temporary buffer.
|
||||
*
|
||||
* 2. uta_remove_rect() the *destination* rectangle from the original
|
||||
* microtile array.
|
||||
*
|
||||
* 3. Copy back the temporary buffer to the original array while
|
||||
* offsetting it in the same way as copy_tile() does.
|
||||
*/
|
||||
|
||||
utiles = uta->utiles;
|
||||
|
||||
rect_x1 = src_x >> ART_UTILE_SHIFT;
|
||||
rect_y1 = src_y >> ART_UTILE_SHIFT;
|
||||
rect_x2 = (src_x + width + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
rect_y2 = (src_y + height + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
|
||||
xofs = dest_x - src_x;
|
||||
yofs = dest_y - src_y;
|
||||
|
||||
left_to_right = xofs < 0;
|
||||
top_to_bottom = yofs < 0;
|
||||
|
||||
if (top_to_bottom && left_to_right) {
|
||||
for (y = rect_y1; y < rect_y2; y++)
|
||||
for (x = rect_x1; x < rect_x2; x++)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (top_to_bottom && !left_to_right) {
|
||||
for (y = rect_y1; y < rect_y2; y++)
|
||||
for (x = rect_x2 - 1; x >= rect_x1; x--)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (!top_to_bottom && left_to_right) {
|
||||
for (y = rect_y2 - 1; y >= rect_y1; y--)
|
||||
for (x = rect_x1; x < rect_x2; x++)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (!top_to_bottom && !left_to_right) {
|
||||
for (y = rect_y2 - 1; y >= rect_y1; y--)
|
||||
for (x = rect_x2 - 1; x >= rect_x1; x--)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ void uta_remove_rect (ArtUta *uta, int x1, int y1, int x2, int y2);
|
|||
|
||||
void uta_find_first_glom_rect (ArtUta *uta, ArtIRect *rect, int max_width, int max_height);
|
||||
|
||||
void uta_copy_area (ArtUta *uta, int src_x, int src_y, int dest_x, int dest_y, int width, int height);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
2000-04-21 Federico Mena Quintero <federico@helixcode.com>
|
||||
|
||||
* image-view.c (scroll_to): New function to do proper scrolling of
|
||||
the image view.
|
||||
(drag_to): Use scroll_to().
|
||||
(adjustment_changed_cb): Use scroll_to().
|
||||
|
||||
* uta.c (uta_copy_area): New function to do the equivalent of a
|
||||
BitBlt on a microtile array. It is not perfect; see the FIXME for
|
||||
details.
|
||||
(copy_tile): Helper function for uta_copy_area().
|
||||
(uta_ensure_size): Create a new uta with the proper size if the
|
||||
specified uta is NULL.
|
||||
(uta_add_rect): Special-case source tiles that are empty so as not
|
||||
to add a bigger region than needed.
|
||||
|
||||
2000-04-20 Federico Mena Quintero <federico@helixcode.com>
|
||||
|
||||
* window.c (window_open_image): Add the image size to the window
|
||||
|
|
158
src/image-view.c
158
src/image-view.c
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <gtk/gtksignal.h>
|
||||
#include "cursors.h"
|
||||
#include "image-view.h"
|
||||
|
@ -57,6 +58,9 @@ typedef struct {
|
|||
GtkAdjustment *hadj;
|
||||
GtkAdjustment *vadj;
|
||||
|
||||
/* Current scrolling offsets */
|
||||
int xofs, yofs;
|
||||
|
||||
/* Microtile array for dirty region */
|
||||
ArtUta *uta;
|
||||
|
||||
|
@ -324,12 +328,12 @@ paint_rectangle (ImageView *view, ArtIRect *rect)
|
|||
if (scaled_width < width)
|
||||
xofs = (width - scaled_width) / 2;
|
||||
else
|
||||
xofs = -priv->hadj->value;
|
||||
xofs = -priv->xofs;
|
||||
|
||||
if (scaled_height < height)
|
||||
yofs = (height - scaled_height) / 2;
|
||||
else
|
||||
yofs = -priv->vadj->value;
|
||||
yofs = -priv->yofs;
|
||||
|
||||
/* Draw background if necessary, in four steps */
|
||||
|
||||
|
@ -412,6 +416,17 @@ paint_rectangle (ImageView *view, ArtIRect *rect)
|
|||
d.x0 - xofs, d.y0 - yofs);
|
||||
|
||||
gdk_pixbuf_unref (tmp);
|
||||
|
||||
#if 0
|
||||
gdk_draw_line (GTK_WIDGET (view)->window,
|
||||
GTK_WIDGET (view)->style->black_gc,
|
||||
d.x0, d.y0,
|
||||
d.x1 - 1, d.y1 - 1);
|
||||
gdk_draw_line (GTK_WIDGET (view)->window,
|
||||
GTK_WIDGET (view)->style->black_gc,
|
||||
d.x1 - 1, d.y0,
|
||||
d.x0, d.y1 - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Idle handler for the drawing process. We pull a rectangle from the dirty
|
||||
|
@ -480,6 +495,119 @@ request_paint_area (ImageView *view, GdkRectangle *area)
|
|||
}
|
||||
}
|
||||
|
||||
/* Scrolls the view to the specified offsets. Does not perform range checking! */
|
||||
static void
|
||||
scroll_to (ImageView *view, int x, int y)
|
||||
{
|
||||
ImageViewPrivate *priv;
|
||||
int xofs, yofs;
|
||||
GdkWindow *window;
|
||||
GdkGC *gc;
|
||||
int width, height;
|
||||
int src_x, src_y;
|
||||
int dest_x, dest_y;
|
||||
int twidth, theight;
|
||||
GdkEvent *event;
|
||||
|
||||
priv = view->priv;
|
||||
|
||||
/* Compute offsets and check bounds */
|
||||
|
||||
xofs = x - priv->xofs;
|
||||
yofs = y - priv->yofs;
|
||||
|
||||
if (xofs == 0 && yofs == 0)
|
||||
return;
|
||||
|
||||
width = GTK_WIDGET (view)->allocation.width;
|
||||
height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
priv->xofs = x;
|
||||
priv->yofs = y;
|
||||
|
||||
if (abs (xofs) >= width || abs (yofs) >= height) {
|
||||
GdkRectangle area;
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = width;
|
||||
area.height = height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
return;
|
||||
}
|
||||
|
||||
window = GTK_WIDGET (view)->window;
|
||||
|
||||
/* Ensure that the uta has the full size */
|
||||
|
||||
twidth = (width + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
theight = (height + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
|
||||
if (priv->uta)
|
||||
g_assert (priv->idle_id != 0);
|
||||
else
|
||||
priv->idle_id = g_idle_add (paint_iteration_idle, view);
|
||||
|
||||
priv->uta = uta_ensure_size (priv->uta, 0, 0, twidth, theight);
|
||||
|
||||
/* Copy the uta area and add the scrolled-in region */
|
||||
|
||||
src_x = xofs < 0 ? 0 : xofs;
|
||||
src_y = yofs < 0 ? 0 : yofs;
|
||||
dest_x = xofs < 0 ? -xofs : 0;
|
||||
dest_y = yofs < 0 ? -yofs : 0;
|
||||
|
||||
uta_copy_area (priv->uta,
|
||||
src_x, src_y,
|
||||
dest_x, dest_y,
|
||||
width - abs (xofs), height - abs (yofs));
|
||||
|
||||
if (xofs) {
|
||||
int xx;
|
||||
|
||||
xx = xofs < 0 ? 0 : width - xofs;
|
||||
uta_add_rect (priv->uta,
|
||||
xx, 0,
|
||||
xx + abs (xofs), height);
|
||||
}
|
||||
|
||||
if (yofs) {
|
||||
int yy;
|
||||
|
||||
yy = yofs < 0 ? 0 : height - yofs;
|
||||
uta_add_rect (priv->uta,
|
||||
0, yy,
|
||||
width, yy + abs (yofs));
|
||||
}
|
||||
|
||||
/* Copy the window area */
|
||||
|
||||
gc = gdk_gc_new (window);
|
||||
gdk_gc_set_exposures (gc, TRUE);
|
||||
|
||||
gdk_window_copy_area (window,
|
||||
gc,
|
||||
dest_x, dest_y,
|
||||
window,
|
||||
src_x, src_y,
|
||||
width - abs (xofs),
|
||||
height - abs (yofs));
|
||||
|
||||
gdk_gc_destroy (gc);
|
||||
|
||||
/* Process graphics exposures */
|
||||
|
||||
while ((event = gdk_event_get_graphics_expose (window)) != NULL) {
|
||||
gtk_widget_event (GTK_WIDGET (view), event);
|
||||
if (event->expose.count == 0) {
|
||||
gdk_event_free (event);
|
||||
break;
|
||||
}
|
||||
gdk_event_free (event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Widget methods */
|
||||
|
@ -668,8 +796,8 @@ image_view_button_press (GtkWidget *widget, GdkEventButton *event)
|
|||
priv->drag_anchor_x = event->x;
|
||||
priv->drag_anchor_y = event->y;
|
||||
|
||||
priv->drag_ofs_x = priv->hadj->value;
|
||||
priv->drag_ofs_y = priv->vadj->value;
|
||||
priv->drag_ofs_x = priv->xofs;
|
||||
priv->drag_ofs_y = priv->yofs;
|
||||
|
||||
cursor = cursor_get (widget->window, CURSOR_HAND_CLOSED);
|
||||
gdk_pointer_grab (widget->window,
|
||||
|
@ -691,7 +819,6 @@ drag_to (ImageView *view, int x, int y)
|
|||
{
|
||||
ImageViewPrivate *priv;
|
||||
int dx, dy;
|
||||
GdkRectangle area;
|
||||
|
||||
priv = view->priv;
|
||||
|
||||
|
@ -701,6 +828,8 @@ drag_to (ImageView *view, int x, int y)
|
|||
x = CLAMP (priv->drag_ofs_x + dx, 0, priv->hadj->upper - priv->hadj->page_size);
|
||||
y = CLAMP (priv->drag_ofs_y + dy, 0, priv->vadj->upper - priv->vadj->page_size);
|
||||
|
||||
scroll_to (view, x, y);
|
||||
|
||||
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->hadj), view);
|
||||
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->vadj), view);
|
||||
|
||||
|
@ -712,15 +841,6 @@ drag_to (ImageView *view, int x, int y)
|
|||
|
||||
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->hadj), view);
|
||||
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->vadj), view);
|
||||
|
||||
/* FIXME: use copy_area() for the window and the uta */
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = GTK_WIDGET (view)->allocation.width;
|
||||
area.height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
}
|
||||
|
||||
/* Button release handler for the image view */
|
||||
|
@ -791,19 +911,11 @@ adjustment_changed_cb (GtkAdjustment *adj, gpointer data)
|
|||
{
|
||||
ImageView *view;
|
||||
ImageViewPrivate *priv;
|
||||
GdkRectangle area;
|
||||
|
||||
view = IMAGE_VIEW (data);
|
||||
priv = view->priv;
|
||||
|
||||
/* FIXME: use copy_area() for the window and the uta */
|
||||
|
||||
area.x = 0;
|
||||
area.y = 0;
|
||||
area.width = GTK_WIDGET (view)->allocation.width;
|
||||
area.height = GTK_WIDGET (view)->allocation.height;
|
||||
|
||||
request_paint_area (view, &area);
|
||||
scroll_to (view, priv->hadj->value, priv->vadj->value);
|
||||
}
|
||||
|
||||
/* Set_scroll_adjustments handler for the image view */
|
||||
|
|
495
src/uta.c
495
src/uta.c
|
@ -33,7 +33,7 @@
|
|||
* @y1: Top microtile coordinate that must fit in new array.
|
||||
* @x2: Right microtile coordinate that must fit in new array.
|
||||
* @y2: Bottom microtile coordinate that must fit in new array.
|
||||
*
|
||||
*
|
||||
* Ensures that the size of a microtile array is big enough to fit the specified
|
||||
* microtile coordinates. If it is not big enough, the specified @uta will be
|
||||
* freed and a new one will be returned. Otherwise, the original @uta will be
|
||||
|
@ -42,7 +42,7 @@
|
|||
*
|
||||
* Note that the specified coordinates must have already been scaled down by the
|
||||
* ART_UTILE_SHIFT factor.
|
||||
*
|
||||
*
|
||||
* Return value: The same value as @uta if the original microtile array was
|
||||
* big enough to fit the specified microtile coordinates, or a new array if
|
||||
* it needed to be grown. In the second case, the original @uta will be
|
||||
|
@ -56,10 +56,12 @@ uta_ensure_size (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
int new_ofs, ofs;
|
||||
int x, y;
|
||||
|
||||
g_return_val_if_fail (uta != NULL, NULL);
|
||||
g_return_val_if_fail (x1 < x2, NULL);
|
||||
g_return_val_if_fail (y1 < y2, NULL);
|
||||
|
||||
if (!uta)
|
||||
return art_uta_new (x1, y1, x2, y2);
|
||||
|
||||
if (x1 >= uta->x0
|
||||
&& y1 >= uta->y0
|
||||
&& x2 <= uta->x0 + uta->width
|
||||
|
@ -105,10 +107,10 @@ uta_ensure_size (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
* @y1: Top coordinate of rectangle.
|
||||
* @x2: Right coordinate of rectangle.
|
||||
* @y2: Bottom coordinate of rectangle.
|
||||
*
|
||||
*
|
||||
* Adds the specified rectangle to a microtile array. The array is
|
||||
* grown to fit the rectangle if necessary.
|
||||
*
|
||||
*
|
||||
* Return value: The original @uta, or a new microtile array if the original one
|
||||
* needed to be grown to fit the specified rectangle. In the second case, the
|
||||
* original @uta will be freed automatically.
|
||||
|
@ -162,83 +164,133 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
if (rect_y2 - rect_y1 == 1) {
|
||||
if (rect_x2 - rect_x1 == 1) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
} else {
|
||||
/* Leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
|
||||
/* Tiles in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
|
||||
/* Rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
} else {
|
||||
if (rect_x2 - rect_x1 == 1) {
|
||||
/* Topmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
ofs += uta->width;
|
||||
|
||||
/* Tiles in between */
|
||||
for (y = rect_y1 + 1; y < rect_y2 - 1; y++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
ofs += uta->width;
|
||||
}
|
||||
|
||||
/* Bottommost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
} else {
|
||||
/* Top row, leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
/* Top row, in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
/* Top row, rightmost tile */
|
||||
/* Top row, rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, yf1, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (bb), yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
ofs += uta->width - (rect_x2 - rect_x1 - 1);
|
||||
|
||||
|
@ -246,10 +298,15 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
for (y = rect_y1 + 1; y < rect_y2 - 1; y++) {
|
||||
/* Leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
/* Tiles in between */
|
||||
bb = ART_UTA_BBOX_CONS (0, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
|
@ -258,36 +315,56 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
|
||||
/* Rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
ART_UTILE_SIZE);
|
||||
|
||||
ofs += uta->width - (rect_x2 - rect_x1 - 1);
|
||||
}
|
||||
|
||||
/* Bottom row, leftmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
xf1, 0, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (bb), xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
|
||||
/* Bottom row, tiles in between */
|
||||
for (x = rect_x1 + 1; x < rect_x2 - 1; x++) {
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0, 0, ART_UTILE_SIZE, yf2);
|
||||
else
|
||||
utiles[ofs++] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
|
||||
/* Bottom row, rightmost tile */
|
||||
bb = utiles[ofs];
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
if (bb == 0)
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, xf2, yf2);
|
||||
else
|
||||
utiles[ofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (bb), xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (bb), yf2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,7 +378,7 @@ uta_add_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
* @y1: Top coordinate of rectangle.
|
||||
* @x2: Right coordinate of rectangle.
|
||||
* @y2: Bottom coordinate of rectangle.
|
||||
*
|
||||
*
|
||||
* Removes a rectangular region from the specified microtile array. Due to the
|
||||
* way microtile arrays represent regions, the tiles at the edge of the
|
||||
* rectangle may not be clipped exactly.
|
||||
|
@ -363,7 +440,7 @@ uta_remove_rect (ArtUta *uta, int x1, int y1, int x2, int y2)
|
|||
ArtUtaBbox bb;
|
||||
int bb_x1, bb_y1, bb_x2, bb_y2;
|
||||
int bb_cx1, bb_cy1, bb_cx2, bb_cy2;
|
||||
|
||||
|
||||
bb = utiles[ofs];
|
||||
bb_x1 = ART_UTA_BBOX_X0 (bb);
|
||||
bb_y1 = ART_UTA_BBOX_Y0 (bb);
|
||||
|
@ -588,3 +665,285 @@ uta_find_first_glom_rect (ArtUta *uta, ArtIRect *rect, int max_width, int max_he
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Copies a single microtile to another location in the UTA, offsetted by the
|
||||
* specified distance. A microtile can thus end up being added in a single part
|
||||
* to another microtile, in two parts to two horizontally or vertically adjacent
|
||||
* microtiles, or in four parts to a 2x2 square of microtiles.
|
||||
*
|
||||
* This is basically a normal BitBlt but with copying-forwards-to-the-destination
|
||||
* instead of fetching-backwards-from-the-source.
|
||||
*/
|
||||
static void
|
||||
copy_tile (ArtUta *uta, int x, int y, int xofs, int yofs)
|
||||
{
|
||||
ArtUtaBbox *utiles;
|
||||
ArtUtaBbox bb, dbb;
|
||||
int t_x1, t_y1, t_x2, t_y2;
|
||||
int d_x1, d_y1, d_x2, d_y2;
|
||||
int d_tx1, d_ty1;
|
||||
int d_xf1, d_yf1, d_xf2, d_yf2;
|
||||
int dofs;
|
||||
|
||||
utiles = uta->utiles;
|
||||
|
||||
bb = utiles[(y - uta->y0) * uta->width + x - uta->x0];
|
||||
|
||||
if (bb == 0)
|
||||
return;
|
||||
|
||||
t_x1 = ART_UTA_BBOX_X0 (bb) + (x << ART_UTILE_SHIFT);
|
||||
t_y1 = ART_UTA_BBOX_Y0 (bb) + (y << ART_UTILE_SHIFT);
|
||||
t_x2 = ART_UTA_BBOX_X1 (bb) + (x << ART_UTILE_SHIFT);
|
||||
t_y2 = ART_UTA_BBOX_Y1 (bb) + (y << ART_UTILE_SHIFT);
|
||||
|
||||
d_x1 = t_x1 + xofs;
|
||||
d_y1 = t_y1 + yofs;
|
||||
d_x2 = t_x2 + xofs;
|
||||
d_y2 = t_y2 + yofs;
|
||||
|
||||
d_tx1 = d_x1 >> ART_UTILE_SHIFT;
|
||||
d_ty1 = d_y1 >> ART_UTILE_SHIFT;
|
||||
|
||||
dofs = (d_ty1 - uta->y0) * uta->width + d_tx1 - uta->x0;
|
||||
|
||||
d_xf1 = d_x1 & (ART_UTILE_SIZE - 1);
|
||||
d_yf1 = d_y1 & (ART_UTILE_SIZE - 1);
|
||||
d_xf2 = ((d_x2 - 1) & (ART_UTILE_SIZE - 1)) + 1;
|
||||
d_yf2 = ((d_y2 - 1) & (ART_UTILE_SIZE - 1)) + 1;
|
||||
|
||||
if (d_x2 - d_x1 <= ART_UTILE_SIZE - d_xf1) {
|
||||
if (d_y2 - d_y1 <= ART_UTILE_SIZE - d_yf1) {
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
} else {
|
||||
/* Top tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, d_xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs += uta->width;
|
||||
|
||||
/* Bottom tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, 0, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (d_y2 - d_y1 <= ART_UTILE_SIZE - d_yf1) {
|
||||
/* Left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, ART_UTILE_SIZE, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, d_yf1, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
} else {
|
||||
/* Top left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, d_yf1, ART_UTILE_SIZE, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
ART_UTILE_SIZE,
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Top right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 >= uta->y0 && d_ty1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, d_yf1, d_xf2, ART_UTILE_SIZE);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
MIN (ART_UTA_BBOX_Y0 (dbb), d_yf1),
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
ART_UTILE_SIZE);
|
||||
}
|
||||
|
||||
dofs += uta->width - 1;
|
||||
|
||||
/* Bottom left tile */
|
||||
if (d_tx1 >= uta->x0 && d_tx1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
d_xf1, 0, ART_UTILE_SIZE, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
MIN (ART_UTA_BBOX_X0 (dbb), d_xf1),
|
||||
0,
|
||||
ART_UTILE_SIZE,
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
|
||||
dofs++;
|
||||
|
||||
/* Bottom right tile */
|
||||
if (d_tx1 + 1 >= uta->x0 && d_tx1 + 1 < uta->x0 + uta->width
|
||||
&& d_ty1 + 1 >= uta->y0 && d_ty1 + 1 < uta->y0 + uta->height) {
|
||||
dbb = utiles[dofs];
|
||||
if (dbb == 0)
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0, 0, d_xf2, d_yf2);
|
||||
else
|
||||
utiles[dofs] = ART_UTA_BBOX_CONS (
|
||||
0,
|
||||
0,
|
||||
MAX (ART_UTA_BBOX_X1 (dbb), d_xf2),
|
||||
MAX (ART_UTA_BBOX_Y1 (dbb), d_yf2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uta_copy_area:
|
||||
* @uta: A microtile array.
|
||||
* @src_x: Left coordinate of source rectangle.
|
||||
* @src_y: Top coordinate of source rectangle.
|
||||
* @dest_x: Left coordinate of destination.
|
||||
* @dest_y: Top coordinate of destination.
|
||||
* @width: Width of region to copy.
|
||||
* @height: Height of region to copy.
|
||||
*
|
||||
* Copies a rectangular region within a microtile array. The array will not be
|
||||
* expanded if the destination area does not fit within it; rather only the area
|
||||
* that fits will be copied. The source rectangle must be completely contained
|
||||
* within the microtile array.
|
||||
**/
|
||||
void
|
||||
uta_copy_area (ArtUta *uta, int src_x, int src_y, int dest_x, int dest_y, int width, int height)
|
||||
{
|
||||
ArtUtaBbox *utiles;
|
||||
int rect_x1, rect_y1, rect_x2, rect_y2;
|
||||
gboolean top_to_bottom, left_to_right;
|
||||
int xofs, yofs;
|
||||
int x, y;
|
||||
|
||||
g_return_if_fail (uta != NULL);
|
||||
g_return_if_fail (width >= 0 && height >= 0);
|
||||
g_return_if_fail (src_x >= uta->x0 << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_y >= uta->y0 << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_x + width <= (uta->x0 + uta->width) << ART_UTILE_SHIFT);
|
||||
g_return_if_fail (src_y + height <= (uta->y0 + uta->height) << ART_UTILE_SHIFT);
|
||||
|
||||
if ((src_x == dest_x && src_y == dest_y) || width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
/* FIXME: This function is not perfect. It *adds* the copied/offsetted
|
||||
* area to the original contents of the microtile array, thus growing
|
||||
* the region more than needed. The effect should be to "overwrite" the
|
||||
* original contents, just like XCopyArea() does. Care needs to be
|
||||
* taken when the edges of the rectangle do not fall on microtile
|
||||
* boundaries, because tiles may need to be "split".
|
||||
*
|
||||
* Maybe this will work:
|
||||
*
|
||||
* 1. Copy the rectangular array of tiles that form the region to a
|
||||
* temporary buffer.
|
||||
*
|
||||
* 2. uta_remove_rect() the *destination* rectangle from the original
|
||||
* microtile array.
|
||||
*
|
||||
* 3. Copy back the temporary buffer to the original array while
|
||||
* offsetting it in the same way as copy_tile() does.
|
||||
*/
|
||||
|
||||
utiles = uta->utiles;
|
||||
|
||||
rect_x1 = src_x >> ART_UTILE_SHIFT;
|
||||
rect_y1 = src_y >> ART_UTILE_SHIFT;
|
||||
rect_x2 = (src_x + width + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
rect_y2 = (src_y + height + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT;
|
||||
|
||||
xofs = dest_x - src_x;
|
||||
yofs = dest_y - src_y;
|
||||
|
||||
left_to_right = xofs < 0;
|
||||
top_to_bottom = yofs < 0;
|
||||
|
||||
if (top_to_bottom && left_to_right) {
|
||||
for (y = rect_y1; y < rect_y2; y++)
|
||||
for (x = rect_x1; x < rect_x2; x++)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (top_to_bottom && !left_to_right) {
|
||||
for (y = rect_y1; y < rect_y2; y++)
|
||||
for (x = rect_x2 - 1; x >= rect_x1; x--)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (!top_to_bottom && left_to_right) {
|
||||
for (y = rect_y2 - 1; y >= rect_y1; y--)
|
||||
for (x = rect_x1; x < rect_x2; x++)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
} else if (!top_to_bottom && !left_to_right) {
|
||||
for (y = rect_y2 - 1; y >= rect_y1; y--)
|
||||
for (x = rect_x2 - 1; x >= rect_x1; x--)
|
||||
copy_tile (uta, x, y, xofs, yofs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ void uta_remove_rect (ArtUta *uta, int x1, int y1, int x2, int y2);
|
|||
|
||||
void uta_find_first_glom_rect (ArtUta *uta, ArtIRect *rect, int max_width, int max_height);
|
||||
|
||||
void uta_copy_area (ArtUta *uta, int src_x, int src_y, int dest_x, int dest_y, int width, int height);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue