aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--src/mainwindow.c27
-rw-r--r--src/objects.c86
-rw-r--r--src/objects.h18
-rw-r--r--src/presentation.c1
-rw-r--r--src/presentation.h4
-rw-r--r--src/tool_image.c307
-rw-r--r--src/tool_image.h41
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 */