diff options
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | src/mainwindow.c | 118 | ||||
-rw-r--r-- | src/objects.c | 81 | ||||
-rw-r--r-- | src/objects.h | 62 | ||||
-rw-r--r-- | src/presentation.c | 63 | ||||
-rw-r--r-- | src/presentation.h | 23 | ||||
-rw-r--r-- | src/slide_render.c | 38 |
7 files changed, 345 insertions, 45 deletions
diff --git a/Makefile.am b/Makefile.am index d8cf801..1b777f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,11 +9,12 @@ AM_CPPFLAGS = -DDATADIR=\""$(datadir)"\" -I$(top_builddir)/lib -I$(top_srcdir)/l 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/slide_render.c src/objects.c INCLUDES = "-I$(top_srcdir)/data" -EXTRA_DIST += src/presentation.h src/mainwindow.h src/slide_render.h +EXTRA_DIST += src/presentation.h src/mainwindow.h src/slide_render.h \ + src/objects.h colloquiumdir = $(datadir)/colloquium colloquium_DATA = data/colloquium.ui diff --git a/src/mainwindow.c b/src/mainwindow.c index 289a096..904c69f 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -33,6 +33,7 @@ #include "presentation.h" #include "mainwindow.h" #include "slide_render.h" +#include "objects.h" static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget, @@ -138,12 +139,82 @@ static gint close_sig(GtkWidget *window, struct presentation *p) } +static gboolean im_commit_sig(GtkIMContext *im, gchar *str, + struct presentation *p) +{ + return FALSE; +} + + +static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, + struct presentation *p) +{ + gboolean r; + + if ( p->editing_object == NULL ) return FALSE; + + /* Throw the event to the IM context and let it sort things out */ + gtk_im_context_filter_keypress(GTK_IM_CONTEXT(p->im_context), event); + + /* FIXME: Invalidate only the necessary region */ + gdk_window_invalidate_rect(p->drawingarea->window, NULL, FALSE); + + return FALSE; +} + + static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, struct presentation *p) { - printf("%f %f\n", event->x - p->border_offs_x, - event->y - p->border_offs_y); - return 0; + if ( p->editing_object && p->editing_object->empty ) { + delete_object(p->editing_object); + } + + p->editing_object = add_text_object(p->view_slide, + event->x - p->border_offs_x, + event->y - p->border_offs_y); + + gtk_widget_grab_focus(GTK_WIDGET(da)); + + /* FIXME: Invalidate only the necessary region */ + gdk_window_invalidate_rect(p->drawingarea->window, NULL, FALSE); + + return FALSE; +} + + +static void draw_editing_box(cairo_t *cr, double xmin, double ymin, + double width, double height) +{ + cairo_new_path(cr); + cairo_rectangle(cr, xmin, ymin, width, height); + cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); +} + + +static void draw_editing_bits(cairo_t *cr, struct object *o) +{ + switch ( o->type ) { + + case TEXT : + + draw_editing_box(cr, o->x - o->bb_width/2.0, + o->y - o->bb_height/2.0, + o->bb_width, o->bb_height); + break; + + } +} + + +static void check_redraw_slide(struct slide *s) +{ + /* Update necessary? */ + if ( s->object_seq <= s->render_cache_seq ) return; + + render_slide(s); } @@ -154,12 +225,14 @@ static gboolean expose_sig(GtkWidget *da, GdkEventExpose *event, GtkAllocation allocation; double xoff, yoff; + check_redraw_slide(p->view_slide); + cr = gdk_cairo_create(da->window); /* Overall background */ cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); - cairo_set_source_rgb(cr, 0.8, 0.8, 1.0); + cairo_set_source_rgb(cr, 0.9, 0.9, 0.9); cairo_fill(cr); /* Get the overall size */ @@ -168,27 +241,22 @@ static gboolean expose_sig(GtkWidget *da, GdkEventExpose *event, yoff = (allocation.height - p->slide_height)/2.0; p->border_offs_x = xoff; p->border_offs_y = yoff; - cairo_translate(cr, xoff, yoff); - /* Draw the slide from the cache */ cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); - cairo_set_source_surface(cr, p->slides[p->view_slide]->render_cache, - 0.0, 0.0); + cairo_set_source_surface(cr, p->view_slide->render_cache, xoff, yoff); cairo_fill(cr); - cairo_destroy(cr); - - return FALSE; -} + cairo_translate(cr, xoff, yoff); + /* Draw editing bits for selected object */ + if ( p->editing_object != NULL ) { + draw_editing_bits(cr, p->editing_object); + } -static void check_redraw_slide(struct presentation *p, int n) -{ - /* Update necessary? */ - if ( p->slides[n]->object_seq <= p->slides[n]->render_cache_seq ) return; + cairo_destroy(cr); - render_slide(p->slides[n]); + return FALSE; } @@ -235,17 +303,25 @@ int open_mainwindow(struct presentation *p) GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); - g_signal_connect(GTK_OBJECT(p->drawingarea), "button-press-event", - G_CALLBACK(button_press_sig), p); - g_signal_connect(GTK_OBJECT(p->drawingarea), "expose-event", + g_signal_connect(G_OBJECT(p->drawingarea), "button-press-event", + G_CALLBACK(button_press_sig), p); + g_signal_connect(G_OBJECT(p->drawingarea), "key-press-event", + G_CALLBACK(key_press_sig), p); + g_signal_connect(G_OBJECT(p->drawingarea), "expose-event", G_CALLBACK(expose_sig), p); + p->im_context = gtk_im_multicontext_new(); + gtk_im_context_set_client_window(GTK_IM_CONTEXT(p->im_context), + p->drawingarea->window); + g_signal_connect(G_OBJECT(p->im_context), "commit", + G_CALLBACK(im_commit_sig), p); + gtk_window_set_default_size(GTK_WINDOW(p->window), 1024+100, 768+100); gtk_window_set_resizable(GTK_WINDOW(p->window), TRUE); assert(p->num_slides > 0); - check_redraw_slide(p, p->view_slide); + check_redraw_slide(p->view_slide); gtk_widget_show_all(window); return 0; diff --git a/src/objects.c b/src/objects.c new file mode 100644 index 0000000..576eeb8 --- /dev/null +++ b/src/objects.c @@ -0,0 +1,81 @@ +/* + * objects.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 "presentation.h" +#include "objects.h" + + +static struct object *new_object(enum objtype t) +{ + struct object *new; + + new = malloc(sizeof(struct object)); + if ( new == NULL ) return NULL; + + new->type = t; + new->empty = 1; + new->parent = NULL; + + return new; +} + + +static void free_object(struct object *o) +{ + free(o); +} + + +struct object *add_text_object(struct slide *s, double x, double y) +{ + struct object *new; + + new = new_object(TEXT); + if ( add_object_to_slide(s, new) ) { + free_object(new); + return NULL; + } + + new->x = x; new->y = y; + new->bb_width = 10.0; + new->bb_height = 40.0; + new->text = "Hello"; + + s->object_seq++; + + return new; +} + + +void delete_object(struct object *o) +{ + remove_object_from_slide(o->parent, o); + free_object(o); +} diff --git a/src/objects.h b/src/objects.h new file mode 100644 index 0000000..c220b00 --- /dev/null +++ b/src/objects.h @@ -0,0 +1,62 @@ +/* + * presentation.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 OBJECTS_H +#define OBJECTS_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +enum objtype +{ + TEXT, +}; + + +struct object +{ + enum objtype type; + struct slide *parent; + + /* Position of object, the interpretation of which depends on + * the type of the object */ + double x; + double y; + + /* Side of rectangular bounding box of object */ + double bb_width; + double bb_height; + + int empty; + + /* For type TEXT */ + char *text; +}; + + +extern struct object *add_text_object(struct slide *s, double x, double y); +extern void delete_object(struct object *o); + + +#endif /* OBJECTS_H */ diff --git a/src/presentation.c b/src/presentation.c index b67c8fd..38b50fc 100644 --- a/src/presentation.c +++ b/src/presentation.c @@ -27,27 +27,29 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> #include "presentation.h" #include "slide_render.h" +#include "objects.h" -int add_slide(struct presentation *p) +struct slide *add_slide(struct presentation *p) { struct slide **try; struct slide *new; - try = realloc(p->slides, p->num_slides*sizeof(struct slide **)); - if ( try == NULL ) return 1; + try = realloc(p->slides, (1+p->num_slides)*sizeof(struct slide *)); + if ( try == NULL ) return NULL; p->slides = try; new = malloc(sizeof(struct slide)); - if ( new == NULL ) return 1; + if ( new == NULL ) return NULL; /* Doesn't matter that p->slides now has some excess space - * it'll get corrected the next time a slide is added or deleted. */ /* No objects to start with */ - new->n_objects = 0; + new->num_objects = 0; new->object_seq = 0; new->objects = NULL; @@ -59,10 +61,55 @@ int add_slide(struct presentation *p) render_slide(new); /* Render nothing, just to make the surface exist */ p->slides[p->num_slides++] = new; + printf("Now %i slides\n", p->num_slides); + return new; +} + + +int add_object_to_slide(struct slide *s, struct object *o) +{ + struct object **try; + + try = realloc(s->objects, (1+s->num_objects)*sizeof(struct object *)); + if ( try == NULL ) return 1; + s->objects = try; + + s->objects[s->num_objects++] = o; + o->parent = s; + + printf("Now %i objects in slide %p\n", s->num_objects, s); + return 0; } +void remove_object_from_slide(struct slide *s, struct object *o) +{ + int i; + int found = 0; + + for ( i=0; i<s->num_objects; i++ ) { + + if ( s->objects[i] == o ) { + assert(!found); + found = 1; + continue; + } + + if ( found ) { + if ( i == s->num_objects-1 ) { + s->objects[i] = NULL; + } else { + s->objects[i] = s->objects[i+1]; + } + } + + } + + s->num_objects--; +} + + struct presentation *new_presentation() { struct presentation *new; @@ -79,11 +126,13 @@ struct presentation *new_presentation() new->slide_width = 1024.0; new->slide_height = 768.0; + /* Add one blank slide and view it */ new->num_slides = 0; new->slides = NULL; - add_slide(new); + new -> view_slide = add_slide(new); + new->view_slide_number = 0; - new->view_slide = 0; + new->editing_object = NULL; return new; } diff --git a/src/presentation.h b/src/presentation.h index 5b219a2..528084d 100644 --- a/src/presentation.h +++ b/src/presentation.h @@ -31,25 +31,13 @@ #include <gtk/gtk.h> -enum objtype -{ - RECTANGLE, -}; - - -struct object -{ - enum objtype type; -}; - - struct slide { cairo_surface_t *render_cache; int render_cache_seq; - int n_objects; - struct object *objects; + int num_objects; + struct object **objects; int object_seq; double slide_width; @@ -66,6 +54,7 @@ struct presentation GtkWidget *drawingarea; GtkUIManager *ui; GtkActionGroup *action_group; + GtkIMContext *im_context; double slide_width; double slide_height; @@ -73,7 +62,9 @@ struct presentation double border_offs_y; /* The slide currently being displayed */ - unsigned int view_slide; + unsigned int view_slide_number; + struct slide *view_slide; + struct object *editing_object; unsigned int num_slides; struct slide **slides; @@ -81,6 +72,8 @@ struct presentation extern struct presentation *new_presentation(void); +extern int add_object_to_slide(struct slide *s, struct object *o); +extern void remove_object_from_slide(struct slide *s, struct object *o); #endif /* PRESENTATION_H */ diff --git a/src/slide_render.c b/src/slide_render.c index 1966fe7..33eee36 100644 --- a/src/slide_render.c +++ b/src/slide_render.c @@ -26,15 +26,40 @@ #endif #include <cairo.h> +#include <pango/pangocairo.h> #include "slide_render.h" #include "presentation.h" +#include "objects.h" + + +static void render_text_object(cairo_t *cr, struct object *o) +{ + PangoLayout *l; + PangoFontDescription *d; + int width, height; + + l = pango_cairo_create_layout(cr); + pango_layout_set_text(l, o->text, -1); + d = pango_font_description_from_string("Sans 30"); + pango_layout_set_font_description(l, d); + pango_font_description_free(d); + + pango_cairo_update_layout(cr, l); + pango_layout_get_size(l, &width, &height); + cairo_move_to(cr, o->x - (width/PANGO_SCALE)/2.0, + o->y - (height/PANGO_SCALE)/2.0); + + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + pango_cairo_show_layout(cr, l); +} int render_slide(struct slide *s) { cairo_surface_t *surf; cairo_t *cr; + int i; surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, s->slide_width, s->slide_height); @@ -45,10 +70,23 @@ int render_slide(struct slide *s) cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_fill(cr); + for ( i=0; i<s->num_objects; i++ ) { + + struct object *o = s->objects[i]; + + switch ( o->type ) { + case TEXT : + render_text_object(cr, o); + break; + } + + } + cairo_destroy(cr); if ( s->render_cache != NULL ) cairo_surface_destroy(s->render_cache); s->render_cache = surf; + s->render_cache_seq = s->object_seq; return 0; } |