diff options
author | Thomas White <taw@bitwiz.org.uk> | 2011-10-13 23:31:15 +0200 |
---|---|---|
committer | Thomas White <taw@bitwiz.org.uk> | 2011-10-13 23:31:15 +0200 |
commit | 2e0f09d78f28c576d9a10dfcd1eeaae81e3baa07 (patch) | |
tree | 9be7b14eefb4451ac6c2a2dccce24625dc3bf7af | |
parent | 7c54f36c7a5352dfd34322397ed322bb377b1abb (diff) |
Add image handling basics
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/mainwindow.c | 27 | ||||
-rw-r--r-- | src/objects.c | 86 | ||||
-rw-r--r-- | src/objects.h | 18 | ||||
-rw-r--r-- | src/presentation.c | 1 | ||||
-rw-r--r-- | src/presentation.h | 4 | ||||
-rw-r--r-- | src/tool_image.c | 307 | ||||
-rw-r--r-- | src/tool_image.h | 41 |
8 files changed, 466 insertions, 20 deletions
diff --git a/Makefile.am b/Makefile.am index dc83c66..ce87b7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,7 +11,7 @@ LDADD = $(top_builddir)/lib/libgnu.a @IGNORE_UNUSED_LIBRARIES_CFLAGS@ src_colloquium_SOURCES = src/colloquium.c src/presentation.c src/mainwindow.c \ src/slide_render.c src/objects.c src/slideshow.c \ src/stylesheet.c src/loadsave.c src/tool_text.c \ - src/tool_select.c + src/tool_select.c src/tool_image.c INCLUDES = "-I$(top_srcdir)/data" diff --git a/src/mainwindow.c b/src/mainwindow.c index e111662..d02268f 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -30,6 +30,7 @@ #include <gtk/gtk.h> #include <assert.h> #include <gdk/gdkkeysyms.h> +#include <gdk-pixbuf/gdk-pixbuf.h> #include "presentation.h" #include "mainwindow.h" @@ -40,6 +41,7 @@ #include "loadsave.h" #include "tool_select.h" #include "tool_text.h" +#include "tool_image.h" static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget, @@ -983,11 +985,27 @@ static void dnd_receive(GtkWidget *widget, GdkDragContext *drag_context, } else { - printf("Drop: '%s'\n", seldata->data); - gtk_drag_finish(drag_context, TRUE, FALSE, time); + gchar *uri; + char *filename; + GError *error = NULL; + + uri = (gchar *)seldata->data; - /* FIXME: Create a new image object according to image size and - * current margins, consistent with box drawn for the preview */ + filename = g_filename_from_uri(uri, NULL, &error); + if ( filename != NULL ) { + + gtk_drag_finish(drag_context, TRUE, FALSE, time); + chomp(filename); + add_image_object(p->view_slide, + p->start_corner_x, p->start_corner_y, + p->import_width, p->import_height, + filename, + p->ss->styles[0], p->image_store, + p->image_tool); + + /* Don't free "filename" - it's now owned by the + * image store. */ + } } } @@ -1047,6 +1065,7 @@ int open_mainwindow(struct presentation *p) p->select_tool = initialise_select_tool(); p->text_tool = initialise_text_tool(p->drawingarea); + p->image_tool = initialise_image_tool(); p->cur_tool = p->select_tool; gtk_widget_set_can_focus(GTK_WIDGET(p->drawingarea), TRUE); diff --git a/src/objects.c b/src/objects.c index 4a1b3db..e926dcc 100644 --- a/src/objects.c +++ b/src/objects.c @@ -28,31 +28,93 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <gdk-pixbuf/gdk-pixbuf.h> #include "presentation.h" #include "objects.h" #include "mainwindow.h" -struct object *add_image_object(struct slide *s, double x, double y, - const char *filename, - double width, double height) +struct image_store { - struct object *new; + int n_images; + struct image *images; +}; - new = NULL; /* FIXME! Generally */ - new->x = x; new->y = y; - new->bb_width = width; - new->bb_height = height; +static struct image *add_image_to_store(struct image_store *is, char *filename) +{ + struct image *images_new; + int idx; + GError *error = NULL; + int w, h; + + images_new = realloc(is->images, (is->n_images+1)*sizeof(struct image)); + if ( images_new == NULL ) { + fprintf(stderr, "Couldn't allocate memory for image.\n"); + return NULL; + } + is->images = images_new; + idx = is->n_images++; + + gdk_pixbuf_get_file_info(filename, &w, &h); - if ( add_object_to_slide(s, new) ) { - delete_object(new); + /* FIXME: If image is huge, load a smaller version */ + is->images[idx].pb = gdk_pixbuf_new_from_file(filename, &error); + if ( is->images[idx].pb == NULL ) { + fprintf(stderr, "Failed to load image '%s'\n", filename); + is->n_images--; return NULL; } - s->object_seq++; + is->images[idx].filename = filename; + is->images[idx].refcount = 1; + is->images[idx].width = w; + is->images[idx].height = h; + + return &is->images[idx]; +} + + +static struct image *find_filename(struct image_store *is, const char *filename) +{ + int i; + + for ( i=0; i<is->n_images; i++ ) { + if ( strcmp(is->images[i].filename, filename) == 0 ) { + return &is->images[i]; + } + } + + return NULL; +} + + +struct image *get_image(struct image_store *is, char *filename) +{ + struct image *image; + + image = find_filename(is, filename); + if ( image == NULL ) { + image = add_image_to_store(is, filename); + } else { + image->refcount++; + } + + return image; +} + + +struct image_store *image_store_new() +{ + struct image_store *is; + + is = calloc(1, sizeof(*is)); + if ( is == NULL ) return NULL; + + is->images = NULL; + is->n_images = 0; - return new; + return is; } diff --git a/src/objects.h b/src/objects.h index 3789261..09d1d29 100644 --- a/src/objects.h +++ b/src/objects.h @@ -56,10 +56,22 @@ struct object void (*delete_object)(struct object *o); }; -extern struct object *add_image_object(struct slide *s, double x, double y, - const char *filename, - double width, double height); +struct image_store; + +struct image +{ + char *filename; + GdkPixbuf *pb; + int width; + int height; + + int refcount; +}; + + +extern struct image *get_image(struct image_store *is, char *filename); +extern struct image_store *image_store_new(void); extern void notify_style_update(struct presentation *p, struct style *sty); diff --git a/src/presentation.c b/src/presentation.c index b05ba4b..68c87c1 100644 --- a/src/presentation.c +++ b/src/presentation.c @@ -223,6 +223,7 @@ struct presentation *new_presentation() new->drag_status = DRAG_STATUS_NONE; new->ss = new_stylesheet(); + new->image_store = image_store_new(); return new; } diff --git a/src/presentation.h b/src/presentation.h index a6acca6..a7db25c 100644 --- a/src/presentation.h +++ b/src/presentation.h @@ -97,6 +97,7 @@ struct presentation struct toolinfo *select_tool; struct toolinfo *text_tool; + struct toolinfo *image_tool; GtkWidget *window; GtkWidget *drawingarea; @@ -148,6 +149,9 @@ struct presentation double import_height; int import_acceptable; + /* All the images used in the presentation */ + struct image_store *image_store; + unsigned int num_slides; struct slide **slides; }; diff --git a/src/tool_image.c b/src/tool_image.c new file mode 100644 index 0000000..af4ada5 --- /dev/null +++ b/src/tool_image.c @@ -0,0 +1,307 @@ +/* + * tool_image.c + * + * Colloquium - A tiny presentation program + * + * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <math.h> +#include <gdk/gdkkeysyms.h> + +#include "presentation.h" +#include "objects.h" +#include "mainwindow.h" +#include "slide_render.h" + + +enum image_drag_reason +{ + IMAGE_DRAG_REASON_NONE, + IMAGE_DRAG_REASON_RESIZE, +}; + + +struct image_toolinfo +{ + struct toolinfo base; + enum image_drag_reason drag_reason; + double box_x; + double box_y; + double box_width; + double box_height; + double drag_offset_x; + double drag_offset_y; +}; + + +struct image_object +{ + struct object base; + + struct image *image; +}; + + +static void update_image(struct image_object *o) +{ + /* FIXME: Implement this */ +} + + +static void render_image_object(cairo_t *cr, struct object *op) +{ + struct image_object *o = (struct image_object *)op; + + cairo_new_path(cr); + cairo_rectangle(cr, op->x, op->y, op->bb_width, op->bb_height); + gdk_cairo_set_source_pixbuf(cr, o->image->pb, op->x, op->y); + cairo_fill(cr); +} + + + +static void update_image_object(struct object *op) +{ + struct image_object *o = (struct image_object *)op; + update_image(o); +} + + +static void delete_image_object(struct object *op) +{ + //struct image_object *o = (struct image_object *)op; +} + + +struct object *add_image_object(struct slide *s, double x, double y, + double bb_width, double bb_height, + char *filename, struct style *sty, + struct image_store *is, + struct image_toolinfo *ti) +{ + struct image_object *new; + + new = calloc(1, sizeof(*new)); + if ( new == NULL ) return NULL; + + /* Base properties */ + new->base.x = x; new->base.y = y; + new->base.bb_width = bb_width; + new->base.bb_height = bb_height; + new->base.type = IMAGE; + new->base.empty = 0; + new->base.parent = NULL; + new->base.style = sty; + + new->image = get_image(is, filename); + if ( new->image == NULL ) { + free(new); + printf("Failed to load or get image.\n"); + return NULL; + } + + /* Methods for this object */ + new->base.render_object = render_image_object; + new->base.delete_object = delete_image_object; + new->base.update_object = update_image_object; + + if ( add_object_to_slide(s, (struct object *)new) ) { + free(new); + return NULL; + } + s->object_seq++; + + update_image(new); + + return (struct object *)new; +} + + +static void click_select(struct presentation *p, struct toolinfo *tip, + double x, double y, GdkEventButton *event, + enum drag_status *drag_status, + enum drag_reason *drag_reason) +{ + double xo, yo; + struct image_toolinfo *ti = (struct image_toolinfo *)tip; + struct image_object *o = (struct image_object *)p->editing_object; + + assert(o->base.type == IMAGE); + + xo = x - o->base.x; yo = y - o->base.y; + + /* Within the resizing region? */ + if ( (xo > o->base.bb_width - 20.0) && (yo > o->base.bb_height - 20.0) ) + { + double cx, cy; + + ti->drag_reason = IMAGE_DRAG_REASON_RESIZE; + + /* Initial size of rubber band box */ + ti->box_x = o->base.x; ti->box_y = o->base.y; + ti->box_width = o->base.bb_width; + ti->box_height = o->base.bb_height; + + /* Coordinates of the bottom right corner */ + cx = o->base.x + o->base.bb_width; + cy = o->base.y + o->base.bb_height; + + ti->drag_offset_x = x - cx; + ti->drag_offset_y = y - cy; + + /* Tell the MCP what we did, and return */ + *drag_status = DRAG_STATUS_DRAGGING; + *drag_reason = DRAG_REASON_TOOL; + return; + } +} + + +static void drag(struct toolinfo *tip, struct presentation *p, + struct object *o, double x, double y) +{ + struct image_toolinfo *ti = (struct image_toolinfo *)tip; + + ti->box_width = x - ti->drag_offset_x - ti->box_x; + ti->box_height = y - ti->drag_offset_y - ti->box_y; + if ( ti->box_width < 20.0 ) ti->box_width = 20.0; + if ( ti->box_height < 20.0 ) ti->box_height = 20.0; + + redraw_overlay(p); +} + + +static void end_drag(struct toolinfo *tip, struct presentation *p, + struct object *o, double x, double y) +{ + struct image_toolinfo *ti = (struct image_toolinfo *)tip; + + ti->box_width = x - ti->drag_offset_x - ti->box_x; + ti->box_height = y - ti->drag_offset_y - ti->box_y; + if ( ti->box_width < 20.0 ) ti->box_width = 20.0; + if ( ti->box_height < 20.0 ) ti->box_height = 20.0; + + o->bb_width = ti->box_width; + o->bb_height = ti->box_height; + update_image((struct image_object *)o); + o->parent->object_seq++; + + ti->drag_reason = IMAGE_DRAG_REASON_NONE; + redraw_overlay(p); +} + + +static void create_region(struct toolinfo *tip, struct presentation *p, + double x1, double y1, double x2, double y2) +{ + //struct object *n; + //struct image_toolinfo *ti = (struct image_toolinfo *)tip; + //struct image_object *o; + + /* FIXME: Open an "Open file" dialogue box and use the result */ +} + + +static void select_object(struct object *o, struct toolinfo *tip) +{ + /* Do nothing */ +} + + +static int deselect_object(struct object *o, struct toolinfo *tip) +{ + if ( (o != NULL) && o->empty ) { + delete_object(o); + return 1; + } + + return 0; +} + + +static void draw_overlay(struct toolinfo *tip, cairo_t *cr, struct object *n) +{ + struct image_toolinfo *ti = (struct image_toolinfo *)tip; + //struct image_object *o = (struct image_object *)n; + + if ( n != NULL ) { + + draw_editing_box(cr, n->x, n->y, n->bb_width, n->bb_height); + + /* Draw resize handle */ + cairo_new_path(cr); + cairo_rectangle(cr, n->x+n->bb_width-20.0, + n->y+n->bb_height-20.0, 20.0, 20.0); + cairo_set_source_rgba(cr, 0.9, 0.9, 0.9, 0.5); + cairo_fill(cr); + } + + if ( ti->drag_reason == IMAGE_DRAG_REASON_RESIZE ) { + + /* FIXME: Use common draw_rubberband_box() routine */ + cairo_new_path(cr); + cairo_rectangle(cr, ti->box_x, ti->box_y, + ti->box_width, ti->box_height); + cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); + cairo_set_line_width(cr, 0.5); + cairo_stroke(cr); + + } + +} + + +static void key_pressed(struct object *o, guint keyval, struct toolinfo *tip) +{ + /* Do nothing */ +} + + +static void im_commit(struct object *o, gchar *str, struct toolinfo *tip) +{ + /* Do nothing */ +} + + +struct toolinfo *initialise_image_tool() +{ + struct image_toolinfo *ti; + + ti = malloc(sizeof(*ti)); + + ti->base.click_select = click_select; + ti->base.create_default = NULL; + ti->base.select = select_object; + ti->base.deselect = deselect_object; + ti->base.drag = drag; + ti->base.end_drag = end_drag; + ti->base.create_region = create_region; + ti->base.draw_editing_overlay = draw_overlay; + ti->base.key_pressed = key_pressed; + ti->base.im_commit = im_commit; + + return (struct toolinfo *)ti; +} diff --git a/src/tool_image.h b/src/tool_image.h new file mode 100644 index 0000000..d4d613b --- /dev/null +++ b/src/tool_image.h @@ -0,0 +1,41 @@ +/* + * tool_image.h + * + * Colloquium - A tiny presentation program + * + * Copyright (c) 2011 Thomas White <taw@bitwiz.org.uk> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef TOOL_IMAGE_H +#define TOOL_IMAGE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtk.h> + + +extern struct toolinfo *initialise_image_tool(void); + +extern struct object *add_image_object(struct slide *s, double x, double y, + double bb_width, double bb_height, + char *filename, struct style *sty, + struct image_store *is, + struct toolinfo *ti); + +#endif /* TOOL_IMAGE_H */ |