diff options
author | Carlos Soriano <csoriano@gnome.org> | 2016-04-22 17:02:38 +0200 |
---|---|---|
committer | Carlos Soriano <csoriano@gnome.org> | 2016-04-25 16:31:42 +0200 |
commit | 7e24f1b2a2b3b7860ee29820d69f5a1511fee994 (patch) | |
tree | a2ee175c5f9cd05ab518e768a073ef4a31fe8376 /src/nautilus-selection-canvas-item.c | |
parent | 2774b8552dcc89ae744700af5832dbf76c138a9e (diff) | |
download | nautilus-7e24f1b2a2b3b7860ee29820d69f5a1511fee994.tar.gz |
general: merge libnautilus-private to srcwip/csoriano/private-to-src
And fix make distcheck.
Although libnautilus-private seem self contained, it was actually
depending on the files on src/ for dnd.
Not only that, but files in libnautilus-private also were depending on
dnd files, which you can guess it's wrong.
Before the desktop split, this was working because the files were
distributed, but now was a problem since we reestructured the code, and
now nautilus being a library make distcheck stop working.
First solution was try to fix this inter dependency of files, but at
some point I realized that there was no real point on splitting some of
those files, because for example, is perfectly fine for dnd to need to
access the window functions, and it's perfectly fine for the widgets
in the private library to need to access to all dnd functions.
So seems to me the private library of nautilus is somehow an artificial
split, which provides more problems than solutions.
We needed libnautilus-private to have a private library that we could
isolate from extensions, but I don't think it worth given the problems
it provides, and also, this not so good logical split.
Right now, since with the desktop split we created a libnautilus to be
used by the desktop part of nautilus, extensions have access to all
the API of nautilus. We will think in future how this can be handled if
we want.
So for now, merge the libnautilus-private into src, and let's rethink
a better logic to split the code and the private parts of nautilus than
what we had.
Thanks a lot to Rafael Fonseca for helping in get this done.
https://bugzilla.gnome.org/show_bug.cgi?id=765543
Diffstat (limited to 'src/nautilus-selection-canvas-item.c')
-rw-r--r-- | src/nautilus-selection-canvas-item.c | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/src/nautilus-selection-canvas-item.c b/src/nautilus-selection-canvas-item.c new file mode 100644 index 000000000..c1619ca8d --- /dev/null +++ b/src/nautilus-selection-canvas-item.c @@ -0,0 +1,712 @@ + +/* Nautilus - Canvas item for floating selection. + * + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * Copyright (C) 2011 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Authors: Federico Mena <federico@nuclecu.unam.mx> + * Cosimo Cecchi <cosimoc@redhat.com> + */ + +#include <config.h> + +#include "nautilus-selection-canvas-item.h" + +#include <math.h> + +enum { + PROP_X1 = 1, + PROP_Y1, + PROP_X2, + PROP_Y2, + PROP_FILL_COLOR_RGBA, + PROP_OUTLINE_COLOR_RGBA, + PROP_OUTLINE_STIPPLING, + PROP_WIDTH_PIXELS, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL }; + +typedef struct { + /*< public >*/ + int x0, y0, x1, y1; +} Rect; + +struct _NautilusSelectionCanvasItemDetails { + Rect last_update_rect; + Rect last_outline_update_rect; + int last_outline_update_width; + + double x1, y1, x2, y2; /* Corners of item */ + double width; /* Outline width */ + + GdkRGBA fill_color; + GdkRGBA outline_color; + + gboolean outline_stippling; + + /* Configuration flags */ + + unsigned int fill_set : 1; /* Is fill color set? */ + unsigned int outline_set : 1; /* Is outline color set? */ + + double fade_out_fill_alpha; + double fade_out_outline_alpha; + + gint64 fade_out_start_time; + gint64 fade_out_end_time; + + guint fade_out_tick_id; +}; + +G_DEFINE_TYPE (NautilusSelectionCanvasItem, nautilus_selection_canvas_item, EEL_TYPE_CANVAS_ITEM); + +#define DASH_ON 0.8 +#define DASH_OFF 1.7 +static void +nautilus_selection_canvas_item_draw (EelCanvasItem *item, + cairo_t *cr, + cairo_region_t *region) +{ + NautilusSelectionCanvasItem *self; + double x1, y1, x2, y2; + int cx1, cy1, cx2, cy2; + double i2w_dx, i2w_dy; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (item); + + /* Get canvas pixel coordinates */ + i2w_dx = 0.0; + i2w_dy = 0.0; + eel_canvas_item_i2w (item, &i2w_dx, &i2w_dy); + + x1 = self->priv->x1 + i2w_dx; + y1 = self->priv->y1 + i2w_dy; + x2 = self->priv->x2 + i2w_dx; + y2 = self->priv->y2 + i2w_dy; + + eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); + eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); + + if (cx2 <= cx1 || cy2 <= cy1 ) { + return; + } + + cairo_save (cr); + + if (self->priv->fill_set) { + GdkRGBA actual_fill; + + actual_fill = self->priv->fill_color; + + if (self->priv->fade_out_tick_id != 0) { + actual_fill.alpha = self->priv->fade_out_fill_alpha; + } + + gdk_cairo_set_source_rgba (cr, &actual_fill); + cairo_rectangle (cr, + cx1, cy1, + cx2 - cx1 + 1, + cy2 - cy1 + 1); + cairo_fill (cr); + } + + if (self->priv->outline_set) { + GdkRGBA actual_outline; + + actual_outline = self->priv->outline_color; + + if (self->priv->fade_out_tick_id != 0) { + actual_outline.alpha = self->priv->fade_out_outline_alpha; + } + + gdk_cairo_set_source_rgba (cr, &actual_outline); + cairo_set_line_width (cr, (int) self->priv->width); + + if (self->priv->outline_stippling) { + double dash[2] = { DASH_ON, DASH_OFF }; + + cairo_set_dash (cr, dash, G_N_ELEMENTS (dash), 0); + } + + cairo_rectangle (cr, + cx1 + 0.5, cy1 + 0.5, + cx2 - cx1, + cy2 - cy1); + cairo_stroke (cr); + } + + cairo_restore (cr); +} + +static double +nautilus_selection_canvas_item_point (EelCanvasItem *item, + double x, + double y, + int cx, + int cy, + EelCanvasItem **actual_item) +{ + NautilusSelectionCanvasItem *self; + double x1, y1, x2, y2; + double hwidth; + double dx, dy; + double tmp; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (item); + *actual_item = item; + + /* Find the bounds for the rectangle plus its outline width */ + + x1 = self->priv->x1; + y1 = self->priv->y1; + x2 = self->priv->x2; + y2 = self->priv->y2; + + if (self->priv->outline_set) { + hwidth = (self->priv->width / item->canvas->pixels_per_unit) / 2.0; + + x1 -= hwidth; + y1 -= hwidth; + x2 += hwidth; + y2 += hwidth; + } else + hwidth = 0.0; + + /* Is point inside rectangle (which can be hollow if it has no fill set)? */ + + if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { + if (self->priv->fill_set || !self->priv->outline_set) + return 0.0; + + dx = x - x1; + tmp = x2 - x; + if (tmp < dx) + dx = tmp; + + dy = y - y1; + tmp = y2 - y; + if (tmp < dy) + dy = tmp; + + if (dy < dx) + dx = dy; + + dx -= 2.0 * hwidth; + + if (dx < 0.0) + return 0.0; + else + return dx; + } + + /* Point is outside rectangle */ + + if (x < x1) + dx = x1 - x; + else if (x > x2) + dx = x - x2; + else + dx = 0.0; + + if (y < y1) + dy = y1 - y; + else if (y > y2) + dy = y - y2; + else + dy = 0.0; + + return sqrt (dx * dx + dy * dy); +} + +static void +request_redraw_borders (EelCanvas *canvas, + Rect *update_rect, + int width) +{ + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y0, + update_rect->x1, update_rect->y0 + width); + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y1-width, + update_rect->x1, update_rect->y1); + eel_canvas_request_redraw (canvas, + update_rect->x0, update_rect->y0, + update_rect->x0+width, update_rect->y1); + eel_canvas_request_redraw (canvas, + update_rect->x1-width, update_rect->y0, + update_rect->x1, update_rect->y1); +} + +static Rect make_rect (int x0, int y0, int x1, int y1); + +static int +rect_empty (const Rect *src) { + return (src->x1 <= src->x0 || src->y1 <= src->y0); +} + +static gboolean +rects_intersect (Rect r1, Rect r2) +{ + if (r1.x0 >= r2.x1) { + return FALSE; + } + if (r2.x0 >= r1.x1) { + return FALSE; + } + if (r1.y0 >= r2.y1) { + return FALSE; + } + if (r2.y0 >= r1.y1) { + return FALSE; + } + return TRUE; +} + +static void +diff_rects_guts (Rect ra, Rect rb, int *count, Rect result[4]) +{ + if (ra.x0 < rb.x0) { + result[(*count)++] = make_rect (ra.x0, ra.y0, rb.x0, ra.y1); + } + if (ra.y0 < rb.y0) { + result[(*count)++] = make_rect (ra.x0, ra.y0, ra.x1, rb.y0); + } + if (ra.x1 < rb.x1) { + result[(*count)++] = make_rect (ra.x1, rb.y0, rb.x1, rb.y1); + } + if (ra.y1 < rb.y1) { + result[(*count)++] = make_rect (rb.x0, ra.y1, rb.x1, rb.y1); + } +} + +static void +diff_rects (Rect r1, Rect r2, int *count, Rect result[4]) +{ + g_assert (count != NULL); + g_assert (result != NULL); + + *count = 0; + + if (rects_intersect (r1, r2)) { + diff_rects_guts (r1, r2, count, result); + diff_rects_guts (r2, r1, count, result); + } else { + if (!rect_empty (&r1)) { + result[(*count)++] = r1; + } + if (!rect_empty (&r2)) { + result[(*count)++] = r2; + } + } +} + +static Rect +make_rect (int x0, int y0, int x1, int y1) +{ + Rect r; + + r.x0 = x0; + r.y0 = y0; + r.x1 = x1; + r.y1 = y1; + return r; +} + +static void +nautilus_selection_canvas_item_update (EelCanvasItem *item, + double i2w_dx, + double i2w_dy, + gint flags) +{ + NautilusSelectionCanvasItem *self; + NautilusSelectionCanvasItemDetails *priv; + double x1, y1, x2, y2; + int cx1, cy1, cx2, cy2; + int repaint_rects_count, i; + int width_pixels; + int width_lt, width_rb; + Rect update_rect, repaint_rects[4]; + + if (EEL_CANVAS_ITEM_CLASS (nautilus_selection_canvas_item_parent_class)->update) + (* EEL_CANVAS_ITEM_CLASS (nautilus_selection_canvas_item_parent_class)->update) (item, i2w_dx, i2w_dy, flags); + + self = NAUTILUS_SELECTION_CANVAS_ITEM (item); + priv = self->priv; + + x1 = priv->x1 + i2w_dx; + y1 = priv->y1 + i2w_dy; + x2 = priv->x2 + i2w_dx; + y2 = priv->y2 + i2w_dy; + + eel_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1); + eel_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2); + + update_rect = make_rect (cx1, cy1, cx2+1, cy2+1); + diff_rects (update_rect, priv->last_update_rect, + &repaint_rects_count, repaint_rects); + for (i = 0; i < repaint_rects_count; i++) { + eel_canvas_request_redraw (item->canvas, + repaint_rects[i].x0, repaint_rects[i].y0, + repaint_rects[i].x1, repaint_rects[i].y1); + } + + priv->last_update_rect = update_rect; + + if (priv->outline_set) { + /* Outline and bounding box */ + width_pixels = (int) priv->width; + width_lt = width_pixels / 2; + width_rb = (width_pixels + 1) / 2; + + cx1 -= width_lt; + cy1 -= width_lt; + cx2 += width_rb; + cy2 += width_rb; + + update_rect = make_rect (cx1, cy1, cx2, cy2); + request_redraw_borders (item->canvas, &update_rect, + (width_lt + width_rb)); + request_redraw_borders (item->canvas, &priv->last_outline_update_rect, + priv->last_outline_update_width); + priv->last_outline_update_rect = update_rect; + priv->last_outline_update_width = width_lt + width_rb; + + item->x1 = cx1; + item->y1 = cy1; + item->x2 = cx2+1; + item->y2 = cy2+1; + } else { + item->x1 = cx1; + item->y1 = cy1; + item->x2 = cx2+1; + item->y2 = cy2+1; + } +} + +static void +nautilus_selection_canvas_item_translate (EelCanvasItem *item, + double dx, + double dy) +{ + NautilusSelectionCanvasItem *self; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (item); + + self->priv->x1 += dx; + self->priv->y1 += dy; + self->priv->x2 += dx; + self->priv->y2 += dy; +} + +static void +nautilus_selection_canvas_item_bounds (EelCanvasItem *item, + double *x1, + double *y1, + double *x2, + double *y2) +{ + NautilusSelectionCanvasItem *self; + double hwidth; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (item); + + hwidth = (self->priv->width / item->canvas->pixels_per_unit) / 2.0; + + *x1 = self->priv->x1 - hwidth; + *y1 = self->priv->y1 - hwidth; + *x2 = self->priv->x2 + hwidth; + *y2 = self->priv->y2 + hwidth; +} + +static gboolean +fade_and_request_redraw (GtkWidget *canvas, + GdkFrameClock *frame_clock, + gpointer user_data) +{ + NautilusSelectionCanvasItem *self = user_data; + gint64 frame_time; + gdouble percentage; + + frame_time = gdk_frame_clock_get_frame_time (frame_clock); + if (frame_time >= self->priv->fade_out_end_time) { + self->priv->fade_out_tick_id = 0; + eel_canvas_item_destroy (EEL_CANVAS_ITEM (self)); + + return G_SOURCE_REMOVE; + } + + percentage = 1.0 - (gdouble) (frame_time - self->priv->fade_out_start_time) / + (gdouble) (self->priv->fade_out_end_time - self->priv->fade_out_start_time); + + self->priv->fade_out_fill_alpha = self->priv->fill_color.alpha * percentage; + self->priv->fade_out_outline_alpha = self->priv->outline_color.alpha * percentage; + + eel_canvas_item_request_redraw (EEL_CANVAS_ITEM (self)); + + return G_SOURCE_CONTINUE; +} + +void +nautilus_selection_canvas_item_fade_out (NautilusSelectionCanvasItem *self, + guint transition_time) +{ + EelCanvasItem *item = EEL_CANVAS_ITEM (self); + GtkWidget *widget; + GdkFrameClock *clock; + + self->priv->fade_out_fill_alpha = self->priv->fill_color.alpha; + self->priv->fade_out_outline_alpha = self->priv->outline_color.alpha; + + widget = GTK_WIDGET (item->canvas); + clock = gtk_widget_get_frame_clock (widget); + self->priv->fade_out_start_time = gdk_frame_clock_get_frame_time (clock); + self->priv->fade_out_end_time = self->priv->fade_out_start_time + 1000 * transition_time; + + self->priv->fade_out_tick_id = + gtk_widget_add_tick_callback (GTK_WIDGET (item->canvas), fade_and_request_redraw, self, NULL); +} + +static void +nautilus_selection_canvas_item_dispose (GObject *obj) +{ + NautilusSelectionCanvasItem *self = NAUTILUS_SELECTION_CANVAS_ITEM (obj); + + if (self->priv->fade_out_tick_id != 0) { + gtk_widget_remove_tick_callback (GTK_WIDGET (EEL_CANVAS_ITEM (self)->canvas), self->priv->fade_out_tick_id); + self->priv->fade_out_tick_id = 0; + } + + G_OBJECT_CLASS (nautilus_selection_canvas_item_parent_class)->dispose (obj); +} + +static void +do_set_fill (NautilusSelectionCanvasItem *self, + gboolean fill_set) +{ + if (self->priv->fill_set != fill_set) { + self->priv->fill_set = fill_set; + eel_canvas_item_request_update (EEL_CANVAS_ITEM (self)); + } +} + +static void +do_set_outline (NautilusSelectionCanvasItem *self, + gboolean outline_set) +{ + if (self->priv->outline_set != outline_set) { + self->priv->outline_set = outline_set; + eel_canvas_item_request_update (EEL_CANVAS_ITEM (self)); + } +} + +static void +nautilus_selection_canvas_item_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EelCanvasItem *item; + NautilusSelectionCanvasItem *self; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (object); + item = EEL_CANVAS_ITEM (object); + + switch (param_id) { + case PROP_X1: + self->priv->x1 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_Y1: + self->priv->y1 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_X2: + self->priv->x2 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_Y2: + self->priv->y2 = g_value_get_double (value); + + eel_canvas_item_request_update (item); + break; + + case PROP_FILL_COLOR_RGBA: { + GdkRGBA *color; + + color = g_value_get_boxed (value); + + do_set_fill (self, color != NULL); + + if (color != NULL) { + self->priv->fill_color = *color; + } + + eel_canvas_item_request_redraw (item); + break; + } + + case PROP_OUTLINE_COLOR_RGBA: { + GdkRGBA *color; + + color = g_value_get_boxed (value); + + do_set_outline (self, color != NULL); + + if (color != NULL) { + self->priv->outline_color = *color; + } + + eel_canvas_item_request_redraw (item); + break; + } + + case PROP_OUTLINE_STIPPLING: + self->priv->outline_stippling = g_value_get_boolean (value); + + eel_canvas_item_request_redraw (item); + break; + + case PROP_WIDTH_PIXELS: + self->priv->width = g_value_get_uint (value); + + eel_canvas_item_request_update (item); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_selection_canvas_item_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusSelectionCanvasItem *self; + + self = NAUTILUS_SELECTION_CANVAS_ITEM (object); + + switch (param_id) { + case PROP_X1: + g_value_set_double (value, self->priv->x1); + break; + + case PROP_Y1: + g_value_set_double (value, self->priv->y1); + break; + + case PROP_X2: + g_value_set_double (value, self->priv->x2); + break; + + case PROP_Y2: + g_value_set_double (value, self->priv->y2); + break; + + case PROP_FILL_COLOR_RGBA: + g_value_set_boxed (value, &self->priv->fill_color); + break; + + case PROP_OUTLINE_COLOR_RGBA: + g_value_set_boxed (value, &self->priv->outline_color); + break; + + case PROP_OUTLINE_STIPPLING: + g_value_set_boolean (value, self->priv->outline_stippling); + break; + case PROP_WIDTH_PIXELS: + g_value_set_uint (value, self->priv->width); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +nautilus_selection_canvas_item_class_init (NautilusSelectionCanvasItemClass *klass) +{ + EelCanvasItemClass *item_class; + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + item_class = EEL_CANVAS_ITEM_CLASS (klass); + + gobject_class->set_property = nautilus_selection_canvas_item_set_property; + gobject_class->get_property = nautilus_selection_canvas_item_get_property; + gobject_class->dispose = nautilus_selection_canvas_item_dispose; + + item_class->draw = nautilus_selection_canvas_item_draw; + item_class->point = nautilus_selection_canvas_item_point; + item_class->update = nautilus_selection_canvas_item_update; + item_class->bounds = nautilus_selection_canvas_item_bounds; + item_class->translate = nautilus_selection_canvas_item_translate; + + properties[PROP_X1] = + g_param_spec_double ("x1", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE); + properties[PROP_Y1] = + g_param_spec_double ("y1", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE); + properties[PROP_X2] = + g_param_spec_double ("x2", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE); + properties[PROP_Y2] = + g_param_spec_double ("y2", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE); + properties[PROP_FILL_COLOR_RGBA] = + g_param_spec_boxed ("fill-color-rgba", NULL, NULL, + GDK_TYPE_RGBA, + G_PARAM_READWRITE); + properties[PROP_OUTLINE_COLOR_RGBA] = + g_param_spec_boxed ("outline-color-rgba", NULL, NULL, + GDK_TYPE_RGBA, + G_PARAM_READWRITE); + properties[PROP_OUTLINE_STIPPLING] = + g_param_spec_boolean ("outline-stippling", NULL, NULL, + FALSE, G_PARAM_READWRITE); + properties[PROP_WIDTH_PIXELS] = + g_param_spec_uint ("width-pixels", NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READWRITE); + + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); + g_type_class_add_private (klass, sizeof (NautilusSelectionCanvasItemDetails)); +} + +static void +nautilus_selection_canvas_item_init (NautilusSelectionCanvasItem *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_SELECTION_CANVAS_ITEM, + NautilusSelectionCanvasItemDetails); +} + + + |