aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--data/colloquium.ui5
-rw-r--r--src/mainwindow.c124
-rw-r--r--src/objects.c206
-rw-r--r--src/objects.h23
-rw-r--r--src/presentation.h6
-rw-r--r--src/slide_render.c107
-rw-r--r--src/stylesheet.c392
-rw-r--r--src/stylesheet.h27
-rw-r--r--src/tool_text.c203
-rw-r--r--src/tool_text.h39
11 files changed, 541 insertions, 596 deletions
diff --git a/Makefile.am b/Makefile.am
index 98e31d7..445f004 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,12 +10,13 @@ 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/stylesheet.c src/loadsave.c src/tool_text.c
INCLUDES = "-I$(top_srcdir)/data"
EXTRA_DIST += src/presentation.h src/mainwindow.h src/slide_render .h \
- src/objects.h src/slideshow.h src/stylesheet.h src/loadsave.h
+ src/objects.h src/slideshow.h src/stylesheet.h src/loadsave.h \
+ src/tool_text.h
colloquiumdir = $(datadir)/colloquium
colloquium_DATA = data/colloquium.ui
diff --git a/data/colloquium.ui b/data/colloquium.ui
index f52500d..532056b 100644
--- a/data/colloquium.ui
+++ b/data/colloquium.ui
@@ -24,6 +24,11 @@
<menuitem name="Stylesheet..." action="EditStyleAction" />
</menu>
+ <menu name="insert" action="InsertAction">
+ <menuitem name="newslide" action="NewSlideAction" />
+ <separator />
+ </menu>
+
<menu name="tools" action="ToolsAction">
<menuitem name="slideshow" action="TSlideshowAction" />
<menuitem name="preferences" action="PrefsAction" />
diff --git a/src/mainwindow.c b/src/mainwindow.c
index b308cfe..3446aed 100644
--- a/src/mainwindow.c
+++ b/src/mainwindow.c
@@ -38,6 +38,7 @@
#include "slideshow.h"
#include "stylesheet.h"
#include "loadsave.h"
+#include "tool_text.h"
static void add_ui_sig(GtkUIManager *ui, GtkWidget *widget,
@@ -255,6 +256,8 @@ static void update_toolbar(struct presentation *p)
gtk_widget_set_sensitive(GTK_WIDGET(d), FALSE);
}
+
+
}
@@ -369,44 +372,11 @@ static gint set_tool_sig(GtkWidget *widget, GtkRadioAction *action,
}
-static void layout_changed_sig(GtkComboBox *combo, struct presentation *p)
-{
- int n;
-
- if ( p->editing_object != NULL ) {
- printf("Can't change layout element!\n");
- return;
- }
-
- n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
- p->cur_layout = p->ss->layout_elements[n];
-
-
-}
-
-
-static void text_style_changed_sig(GtkComboBox *combo, struct presentation *p)
-{
- int n;
-
- n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
- p->cur_style = p->ss->text_styles[n];
-
- if ( p->editing_object != NULL ) {
- set_text_style(p->editing_object, p->cur_style);
- gdk_window_invalidate_rect(p->drawingarea->window, NULL, FALSE);
- }
-}
-
-
static void add_menu_bar(struct presentation *p, GtkWidget *vbox)
{
GError *error = NULL;
- GtkWidget *label;
- GtkWidget *combo;
GtkToolItem *titem;
- GtkWidget *box;
- int i;
+ GtkWidget *toolbar;
GtkActionEntry entries[] = {
{ "FileAction", NULL, "_File", NULL, NULL, NULL },
@@ -439,6 +409,10 @@ static void add_menu_bar(struct presentation *p, GtkWidget *vbox)
{ "EditStyleAction", NULL, "Stylesheet...",
NULL, NULL, G_CALLBACK(open_stylesheet_sig) },
+ { "InsertAction", NULL, "_Insert", NULL, NULL, NULL },
+ { "NewSlideAction", GTK_STOCK_ADD, "_New Slide",
+ NULL, NULL, G_CALLBACK(add_slide_sig) },
+
{ "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
{ "TSlideshowAction", GTK_STOCK_FULLSCREEN, "_Start slideshow",
"F5", NULL, G_CALLBACK(start_slideshow_sig) },
@@ -492,43 +466,15 @@ static void add_menu_bar(struct presentation *p, GtkWidget *vbox)
gtk_ui_manager_get_accel_group(p->ui));
gtk_ui_manager_ensure_update(p->ui);
- p->toolbar = gtk_ui_manager_get_widget(p->ui,
- "/ui/displaywindowtoolbar");
-
+ toolbar = gtk_ui_manager_get_widget(p->ui,
+ "/ui/displaywindowtoolbar");
titem = gtk_separator_tool_item_new();
- gtk_toolbar_insert(GTK_TOOLBAR(p->toolbar), titem, -1);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), titem, -1);
- box = gtk_vbox_new(FALSE, 0.0);
p->tbox = gtk_hbox_new(FALSE, 0.0);
titem = gtk_tool_item_new();
- gtk_box_pack_start(GTK_BOX(box), p->tbox, FALSE, FALSE, 5.0);
- gtk_container_add(GTK_CONTAINER(titem), box);
- gtk_toolbar_insert(GTK_TOOLBAR(p->toolbar), titem, -1);
- label = gtk_label_new("Layout element:");
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_box_pack_start(GTK_BOX(p->tbox), label, FALSE, FALSE, 5.0);
- combo = gtk_combo_box_new_text();
- for ( i=0; i<p->ss->n_layout_elements; i++ ) {
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
- p->ss->layout_elements[i]->name);
- }
- gtk_box_pack_start(GTK_BOX(p->tbox), combo, FALSE, FALSE, 5.0);
- g_signal_connect(G_OBJECT(combo), "changed",
- G_CALLBACK(layout_changed_sig), p);
- gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
-
- label = gtk_label_new("Text style:");
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_box_pack_start(GTK_BOX(p->tbox), label, FALSE, FALSE, 5.0);
- combo = gtk_combo_box_new_text();
- for ( i=0; i<p->ss->n_text_styles; i++ ) {
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
- p->ss->text_styles[i]->name);
- }
- gtk_box_pack_start(GTK_BOX(p->tbox), combo, FALSE, FALSE, 5.0);
- g_signal_connect(G_OBJECT(combo), "changed",
- G_CALLBACK(text_style_changed_sig), p);
- gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
+ gtk_container_add(GTK_CONTAINER(titem), p->tbox);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), titem, -1);
update_toolbar(p);
}
@@ -670,9 +616,10 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event,
case TOOL_TEXT :
if ( !clicked ) {
struct object *n;
+ /* FIXME: Insert ESP here and possibly
+ * select a different style */
n = add_text_object(p->view_slide, x, y,
- p->cur_layout,
- p->cur_style);
+ p->ss->styles[0]);
p->editing_object = n;
} else {
p->editing_object = clicked;
@@ -707,6 +654,7 @@ static void draw_editing_bits(cairo_t *cr, struct presentation *p,
{
draw_editing_box(cr, o->x, o->y, o->bb_width, o->bb_height);
+ /* FIXME: Dispatch table */
switch ( o->type ) {
case TEXT :
@@ -716,31 +664,27 @@ static void draw_editing_bits(cairo_t *cr, struct presentation *p,
}
- if ( o->le != NULL ) {
-
- cairo_move_to(cr, o->le->margin_left, -p->border_offs_y);
- cairo_line_to(cr, o->le->margin_left,
- p->slide_height+p->border_offs_y);
+ cairo_move_to(cr, o->style->margin_left, -p->border_offs_y);
+ cairo_line_to(cr, o->style->margin_left,
+ p->slide_height+p->border_offs_y);
- cairo_move_to(cr, p->slide_width-o->le->margin_right,
- -p->border_offs_y);
- cairo_line_to(cr, p->slide_width-o->le->margin_right,
- p->slide_height+p->border_offs_y);
+ cairo_move_to(cr, p->slide_width-o->style->margin_right,
+ -p->border_offs_y);
+ cairo_line_to(cr, p->slide_width-o->style->margin_right,
+ p->slide_height+p->border_offs_y);
- cairo_move_to(cr, -p->border_offs_x, o->le->margin_top);
- cairo_line_to(cr, p->slide_width+p->border_offs_x,
- o->le->margin_top);
+ cairo_move_to(cr, -p->border_offs_x, o->style->margin_top);
+ cairo_line_to(cr, p->slide_width+p->border_offs_x,
+ o->style->margin_top);
- cairo_move_to(cr, -p->border_offs_x,
- p->slide_height-o->le->margin_bottom);
- cairo_line_to(cr, p->slide_width+p->border_offs_x,
- p->slide_height-o->le->margin_bottom);
+ cairo_move_to(cr, -p->border_offs_x,
+ p->slide_height-o->style->margin_bottom);
+ cairo_line_to(cr, p->slide_width+p->border_offs_x,
+ p->slide_height-o->style->margin_bottom);
- cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
- cairo_set_line_width(cr, 1.0);
- cairo_stroke(cr);
-
- }
+ cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
}
diff --git a/src/objects.c b/src/objects.c
index ae634a5..4d18df1 100644
--- a/src/objects.c
+++ b/src/objects.c
@@ -34,7 +34,7 @@
#include "mainwindow.h"
-static struct object *new_object(enum objtype t, struct layout_element *le)
+struct object *new_object(enum objtype t, struct style *sty)
{
struct object *new;
@@ -44,13 +44,13 @@ static struct object *new_object(enum objtype t, struct layout_element *le)
new->type = t;
new->empty = 1;
new->parent = NULL;
- new->le = le;
+ new->style = sty;
return new;
}
-static void free_object(struct object *o)
+void free_object(struct object *o)
{
if ( o->layout != NULL ) g_object_unref(o->layout);
if ( o->fontdesc != NULL ) pango_font_description_free(o->fontdesc);
@@ -58,207 +58,29 @@ static void free_object(struct object *o)
}
-struct object *add_text_object(struct slide *s, double x, double y,
- struct layout_element *el, struct text_style *ts)
+struct object *add_image_object(struct slide *s, double x, double y,
+ const char *filename,
+ double width, double height)
{
struct object *new;
- new = new_object(TEXT, el);
+ new = new_object(IMAGE, NULL);
+
+ new->x = x; new->y = y;
+ new->bb_width = width;
+ new->bb_height = height;
+
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 = malloc(1);
- new->text[0] = '\0';
- new->text_len = 1;
- new->insertion_point = 0;
- new->style = ts;
- new->layout = NULL;
- new->fontdesc = NULL;
-
s->object_seq++;
return new;
}
-void insert_text(struct object *o, char *t)
-{
- char *tmp;
- size_t tlen, olen;
- int i;
-
- assert(o->type == TEXT);
- tlen = strlen(t);
- olen = strlen(o->text);
-
- if ( tlen + olen + 1 > o->text_len ) {
-
- char *try;
-
- try = realloc(o->text, o->text_len + tlen + 64);
- if ( try == NULL ) return; /* Failed to insert */
- o->text = try;
- o->text_len += 64;
- o->text_len += tlen;
-
- }
-
- tmp = malloc(o->text_len);
- if ( tmp == NULL ) return;
-
- for ( i=0; i<o->insertion_point; i++ ) {
- tmp[i] = o->text[i];
- }
- for ( i=0; i<tlen; i++ ) {
- tmp[i+o->insertion_point] = t[i];
- }
- for ( i=0; i<olen-o->insertion_point; i++ ) {
- tmp[i+o->insertion_point+tlen] = o->text[i+o->insertion_point];
- }
- tmp[olen+tlen] = '\0';
- memcpy(o->text, tmp, o->text_len);
- free(tmp);
-
- o->insertion_point += tlen;
- o->parent->object_seq++;
- o->empty = 0;
-}
-
-
-void set_text_style(struct object *o, struct text_style *ts)
-{
- assert(o->type == TEXT);
- o->style = ts;
- o->parent->object_seq++;
-}
-
-
-static int find_prev_index(const char *t, int p)
-{
- int i, nback;
-
- if ( p == 0 ) return 0;
-
- if ( !(t[p-1] & 0x80) ) {
- nback = 1;
- } else {
- nback = 0;
- for ( i=1; i<=6; i++ ) {
- if ( p-i == 0 ) return 0;
- if ( !(t[p-i] & 0xC0) ) nback++;
- }
- }
-
- return p - nback;
-}
-
-
-static int find_next_index(const char *t, int p)
-{
- int i, nfor;
-
- if ( t[p] == '\0' ) return p;
-
- if ( !(t[p+1] & 0x80) ) {
- nfor = 1;
- } else {
- nfor = 0;
- for ( i=1; i<=6; i++ ) {
- if ( t[p+i] == '\0' ) return p+i;
- if ( !(t[p+i] & 0xC0) ) nfor++;
- }
- }
-
- return p + nfor;
-}
-
-
-void handle_text_backspace(struct object *o)
-{
- int prev_index;
-
- assert(o->type == TEXT);
-
- if ( o->insertion_point == 0 ) return; /* Nothing to delete */
-
- prev_index = find_prev_index(o->text, o->insertion_point);
-
- memmove(o->text+prev_index, o->text+o->insertion_point,
- o->text_len-o->insertion_point);
-
- o->insertion_point = prev_index;
-
- if ( strlen(o->text) == 0 ) o->empty = 1;
-
- o->parent->object_seq++;
-}
-
-
-void move_cursor_left(struct object *o)
-{
- o->insertion_point = find_prev_index(o->text, o->insertion_point);
-}
-
-
-void move_cursor_right(struct object *o)
-{
- o->insertion_point = find_next_index(o->text, o->insertion_point);
-}
-
-
-void position_caret(struct object *o, double x, double y)
-{
- int idx, trail;
- int xp, yp;
- gboolean v;
-
- assert(o->type == TEXT);
-
- xp = (x - o->x)*PANGO_SCALE;
- yp = (y - o->y)*PANGO_SCALE;
-
- v = pango_layout_xy_to_index(o->layout, xp, yp, &idx, &trail);
-
- o->insertion_point = idx+trail;
-}
-
-
-void notify_style_update(struct presentation *p, struct text_style *ts)
-{
- int i;
- int changed = 0;
-
- for ( i=0; i<p->num_slides; i++ ) {
-
- int j;
- struct slide *s;
-
- s = p->slides[i];
-
- for ( j=0; j<p->slides[i]->num_objects; j++ ) {
-
- if ( s->objects[j]->type != TEXT ) continue;
- if ( s->objects[j]->style != ts ) continue;
-
- s->object_seq++;
- if ( p->view_slide == s ) changed = 1;
- break;
-
- }
-
- }
-
- p->completely_empty = 0;
- if ( changed ) notify_slide_update(p);
-}
-
-
-void notify_layout_update(struct presentation *p, struct layout_element *le)
+void notify_style_update(struct presentation *p, struct style *sty)
{
int i;
int changed = 0;
@@ -272,7 +94,7 @@ void notify_layout_update(struct presentation *p, struct layout_element *le)
for ( j=0; j<p->slides[i]->num_objects; j++ ) {
- if ( s->objects[j]->le != le ) continue;
+ if ( s->objects[j]->style != sty ) continue;
s->object_seq++;
if ( p->view_slide == s ) changed = 1;
diff --git a/src/objects.h b/src/objects.h
index ddbd2a8..d7eb706 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -31,6 +31,7 @@
enum objtype
{
TEXT,
+ IMAGE,
};
@@ -38,7 +39,7 @@ struct object
{
enum objtype type;
struct slide *parent;
- struct layout_element *le;
+ struct style *style;
/* Position of corner of object */
double x;
@@ -56,23 +57,17 @@ struct object
int insertion_point;
PangoLayout *layout;
PangoFontDescription *fontdesc;
- struct text_style *style;
};
+extern struct object *new_object(enum objtype t, struct style *sty);
+extern void free_object(struct object *o);
+extern struct object *add_image_object(struct slide *s, double x, double y,
+ const char *filename,
+ double width, double height);
-extern struct object *add_text_object(struct slide *s, double x, double y,
- struct layout_element *el,
- struct text_style *ts);
-extern void insert_text(struct object *o, char *t);
-extern void set_text_style(struct object *o, struct text_style *ts);
-extern void notify_style_update(struct presentation *p, struct text_style *ts);
-extern void handle_text_backspace(struct object *o);
-extern void move_cursor_left(struct object *o);
-extern void move_cursor_right(struct object *o);
-extern void position_caret(struct object *o, double x, double y);
-extern void notify_layout_update(struct presentation *p,
- struct layout_element *ts);
+extern void notify_style_update(struct presentation *p,
+ struct style *sty);
extern void delete_object(struct object *o);
diff --git a/src/presentation.h b/src/presentation.h
index d48fd96..db53f07 100644
--- a/src/presentation.h
+++ b/src/presentation.h
@@ -67,7 +67,6 @@ struct presentation
GtkUIManager *ui;
GtkActionGroup *action_group;
GtkIMContext *im_context;
- GtkWidget *toolbar;
GtkWidget *tbox;
int drag_preview_pending;
int have_drag_data;
@@ -79,9 +78,8 @@ struct presentation
int drag_y;
/* Stylesheet */
- StyleSheet *ss;
- struct text_style *cur_style;
- struct layout_element *cur_layout;
+ StyleSheet *ss;
+ struct style *default_style;
/* Dialogue boxes */
StylesheetWindow *stylesheetwindow;
diff --git a/src/slide_render.c b/src/slide_render.c
index 3a34f6a..8c438d4 100644
--- a/src/slide_render.c
+++ b/src/slide_render.c
@@ -35,38 +35,37 @@
#include "stylesheet.h"
-static void render_text_object(cairo_t *cr, struct object *o)
+static void calculate_size_from_style(struct object *o,
+ double *peright, double *pebottom,
+ double *pmw, double *pmh)
{
- double ebottom, eright, mw, mh;
double max_width, max_height;
- double xo, yo;
- PangoRectangle ink, logical;
-
- o->layout = pango_cairo_create_layout(cr);
- pango_layout_set_text(o->layout, o->text, -1);
- o->fontdesc = pango_font_description_from_string(o->style->font);
- pango_layout_set_font_description(o->layout, o->fontdesc);
+ double ebottom, eright, mw, mh;
- eright = o->parent->slide_width - o->le->margin_right;
- ebottom = o->parent->slide_height - o->le->margin_bottom;
+ eright = o->parent->slide_width - o->style->margin_right;
+ ebottom = o->parent->slide_height - o->style->margin_bottom;
mw = o->parent->slide_width;
mh = o->parent->slide_height;
- max_width = mw - o->le->margin_left - o->le->margin_right;
+ *peright = eright; *pebottom = ebottom;
+ *pmw = mw; *pmh = mh;
+
+ max_width = mw - o->style->margin_left - o->style->margin_right;
/* Use the provided maximum width if it exists and is smaller */
- if ( o->le->use_max_width && (o->le->max_width < max_width) ) {
- max_width = o->le->max_width;
+ if ( o->style->use_max_width && (o->style->max_width < max_width) )
+ {
+ max_width = o->style->max_width;
}
- max_height = mh - o->le->margin_top - o->le->margin_bottom;
+ max_height = mh - o->style->margin_top - o->style->margin_bottom;
pango_layout_set_width(o->layout, max_width*PANGO_SCALE);
pango_layout_set_height(o->layout, max_height*PANGO_SCALE);
pango_layout_set_wrap(o->layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(o->layout, PANGO_ELLIPSIZE_MIDDLE);
- switch ( o->le->halign ) {
+ switch ( o->style->halign ) {
case J_LEFT :
pango_layout_set_alignment(o->layout, PANGO_ALIGN_LEFT);
break;
@@ -77,66 +76,100 @@ static void render_text_object(cairo_t *cr, struct object *o)
pango_layout_set_alignment(o->layout, PANGO_ALIGN_CENTER);
break;
}
+}
- pango_cairo_update_layout(cr, o->layout);
+
+static void calculate_position_from_style(struct object *o,
+ double eright, double ebottom,
+ double mw, double mh)
+{
+ double xo, yo;
+ PangoRectangle ink, logical;
pango_layout_get_extents(o->layout, &ink, &logical);
- o->bb_width = ink.width / PANGO_SCALE;
- o->bb_height = logical.height/PANGO_SCALE;
xo = ink.x/PANGO_SCALE; yo = logical.y/PANGO_SCALE;
- switch ( o->le->halign ) {
+ switch ( o->style->halign ) {
case J_LEFT :
- o->x = -xo + o->le->margin_left;
+ o->x = -xo + o->style->margin_left;
break;
case J_RIGHT :
o->x = -xo + eright - o->bb_width;
break;
case J_CENTER :
- o->x = mw/2.0 - o->bb_width/2.0 - xo + o->le->offset_x;
+ o->x = mw/2.0 - o->bb_width/2.0 - xo + o->style->offset_x;
break;
}
- if ( o->le->halign == J_CENTER ) {
+ if ( o->style->halign == J_CENTER ) {
- if ( o->x+xo < o->le->margin_left ) {
- o->x = o->le->margin_left - xo;
+ if ( o->x+xo < o->style->margin_left ) {
+ o->x = o->style->margin_left - xo;
}
- if ( o->x+xo + o->bb_width > mw-o->le->margin_right ) {
- o->x = mw-o->le->margin_right - xo - o->bb_width;
+ if ( o->x+xo + o->bb_width > mw-o->style->margin_right ) {
+ o->x = mw-o->style->margin_right - xo - o->bb_width;
}
}
- switch ( o->le->valign ) {
+ switch ( o->style->valign ) {
case V_TOP :
- o->y = o->le->margin_top;
+ o->y = o->style->margin_top;
break;
case V_BOTTOM :
o->y = ebottom - o->bb_height;
break;
case V_CENTER :
- o->y = mh/2.0 - o->bb_height/2.0 + yo - o->le->offset_y;
+ o->y = mh/2.0 - o->bb_height/2.0 + yo - o->style->offset_y;
break;
}
- if ( o->le->valign == V_CENTER ) {
+ if ( o->style->valign == V_CENTER ) {
- if ( o->y < o->le->margin_top ) {
- o->y = o->le->margin_top;
+ if ( o->y < o->style->margin_top ) {
+ o->y = o->style->margin_top;
}
- if ( o->y+yo + o->bb_height > mh - o->le->margin_bottom ) {
- o->y = mh-o->le->margin_bottom - yo - o->bb_height;
+ if ( o->y+yo + o->bb_height > mh - o->style->margin_bottom ) {
+ o->y = mh-o->style->margin_bottom - yo - o->bb_height;
}
}
+ o->x += xo;
+ o->y += yo;
+}
+
+
+static void render_text_object(cairo_t *cr, struct object *o)
+{
+ PangoRectangle ink, logical;
+ double eright, ebottom, mw, mh;
+
+ o->layout = pango_cairo_create_layout(cr);
+ pango_layout_set_text(o->layout, o->text, -1);
+ o->fontdesc = pango_font_description_from_string(o->style->font);
+ pango_layout_set_font_description(o->layout, o->fontdesc);
+
+ if ( o->style != o->parent->parent->ss->styles[0] )
+ {
+ calculate_size_from_style(o, &eright, &ebottom, &mw, &mh);
+ }
+
+ pango_cairo_update_layout(cr, o->layout);
+
+ pango_layout_get_extents(o->layout, &ink, &logical);
+ o->bb_width = ink.width / PANGO_SCALE;
+ o->bb_height = logical.height/PANGO_SCALE;
+
+ if ( o->style != o->parent->parent->ss->styles[0] )
+ {
+ calculate_position_from_style(o, eright, ebottom, mw, mh);
+ }
+
cairo_move_to(cr, o->x, o->y);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
pango_cairo_show_layout(cr, o->layout);
- o->x += xo;
- o->y += yo;
}
diff --git a/src/stylesheet.c b/src/stylesheet.c
index 46167a1..b4cc11e 100644
--- a/src/stylesheet.c
+++ b/src/stylesheet.c
@@ -57,38 +57,20 @@ struct _stylesheetwindow
GtkWidget *max_width;
GtkWidget *use_max;
- struct text_style *cur_text_style;
- struct layout_element *cur_layout_element;
+ struct style *cur_style;
};
-static void text_changed_sig(GtkComboBox *combo,
- struct _stylesheetwindow *s)
-{
- int n;
- GdkColor col;
-
- n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
- s->cur_text_style = s->ss->text_styles[n];
-
- gtk_font_button_set_font_name(GTK_FONT_BUTTON(s->text_font),
- s->cur_text_style->font);
-
- gdk_color_parse(s->cur_text_style->colour, &col);
- gtk_color_button_set_color(GTK_COLOR_BUTTON(s->text_colour), &col);
-}
-
-
static void text_font_set_sig(GtkFontButton *widget,
struct _stylesheetwindow *s)
{
const gchar *font;
font = gtk_font_button_get_font_name(widget);
- free(s->cur_text_style->font);
- s->cur_text_style->font = strdup(font);
+ free(s->cur_style->font);
+ s->cur_style->font = strdup(font);
- notify_style_update(s->p, s->cur_text_style);
+ notify_style_update(s->p, s->cur_style);
}
@@ -99,147 +81,84 @@ static void text_colour_set_sig(GtkColorButton *widget,
guint16 al;
gtk_color_button_get_color(widget, &col);
- free(s->cur_text_style->colour);
- s->cur_text_style->colour = gdk_color_to_string(&col);
+ free(s->cur_style->colour);
+ s->cur_style->colour = gdk_color_to_string(&col);
al = gtk_color_button_get_alpha(widget);
- s->cur_text_style->alpha = (double)al / 65535.0;
+ s->cur_style->alpha = (double)al / 65535.0;
- notify_style_update(s->p, s->cur_text_style);
-}
-
-
-static void do_text(struct _stylesheetwindow *s, GtkWidget *b)
-{
- GtkWidget *table;
- GtkWidget *box;
- GtkWidget *line;
- GtkWidget *label;
- GtkWidget *combo;
- GtkWidget *vbox;
- int i;
-
- vbox = gtk_vbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(b), vbox, TRUE, TRUE, 0);
-
- table = gtk_table_new(4, 2, FALSE);
- gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5);
- gtk_table_set_row_spacings(GTK_TABLE(table), 5.0);
- gtk_table_set_col_spacings(GTK_TABLE(table), 5.0);
-
- label = gtk_label_new("Style:");
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
- combo = gtk_combo_box_new_text();
- gtk_table_attach_defaults(GTK_TABLE(table), combo, 1, 4, 0, 1);
-
- for ( i=0; i<s->ss->n_text_styles; i++ ) {
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
- s->ss->text_styles[i]->name);
- }
- gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
- gtk_widget_set_size_request(GTK_WIDGET(combo), 300, -1);
- g_signal_connect(G_OBJECT(combo), "changed",
- G_CALLBACK(text_changed_sig), s);
-
- line = gtk_hseparator_new();
- gtk_table_attach_defaults(GTK_TABLE(table), line, 0, 4, 1, 2);
- gtk_table_set_row_spacing(GTK_TABLE(table), 0, 10);
- gtk_table_set_row_spacing(GTK_TABLE(table), 1, 10);
-
- label = gtk_label_new("Font:");
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
- s->text_font = gtk_font_button_new_with_font("Sans 12");
- box = gtk_hbox_new(FALSE, 0);
- gtk_table_attach_defaults(GTK_TABLE(table), box, 1, 2, 2, 3);
- gtk_box_pack_start(GTK_BOX(box), s->text_font, FALSE, FALSE, 0);
- g_signal_connect(G_OBJECT(s->text_font), "font-set",
- G_CALLBACK(text_font_set_sig), s);
-
- label = gtk_label_new("Colour:");
- gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
- gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
- s->text_colour = gtk_color_button_new();
- box = gtk_hbox_new(FALSE, 0);
- gtk_table_attach_defaults(GTK_TABLE(table), box, 1, 2, 3, 4);
- gtk_box_pack_start(GTK_BOX(box), s->text_colour, FALSE, FALSE, 0);
- g_signal_connect(G_OBJECT(s->text_colour), "color-set",
- G_CALLBACK(text_colour_set_sig), s);
-
- /* Force first update */
- text_changed_sig(GTK_COMBO_BOX(combo), s);
+ notify_style_update(s->p, s->cur_style);
}
static void margin_left_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->margin_left = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->margin_left = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void margin_right_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->margin_right = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->margin_right = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void margin_top_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->margin_top = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->margin_top = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void margin_bottom_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->margin_bottom = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->margin_bottom = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void offset_x_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->offset_x = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->offset_x = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void offset_y_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->offset_y = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->offset_y = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
static void halign_changed_sig(GtkComboBox *combo,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->halign = gtk_combo_box_get_active(combo);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->halign = gtk_combo_box_get_active(combo);
+ notify_style_update(s->p, s->cur_style);
}
static void valign_changed_sig(GtkComboBox *combo,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->valign = gtk_combo_box_get_active(combo);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->valign = gtk_combo_box_get_active(combo);
+ notify_style_update(s->p, s->cur_style);
}
static void max_changed_sig(GtkSpinButton *spin,
struct _stylesheetwindow *s)
{
- s->cur_layout_element->max_width = gtk_spin_button_get_value(spin);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->max_width = gtk_spin_button_get_value(spin);
+ notify_style_update(s->p, s->cur_style);
}
@@ -249,45 +168,56 @@ static void use_max_toggled_sig(GtkToggleButton *combo,
int v;
v = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->use_max));
- s->cur_layout_element->use_max_width = v;
+ s->cur_style->use_max_width = v;
gtk_widget_set_sensitive(s->max_width,
- s->cur_layout_element->use_max_width);
- notify_layout_update(s->p, s->cur_layout_element);
+ s->cur_style->use_max_width);
+ notify_style_update(s->p, s->cur_style);
}
-static void layout_changed_sig(GtkComboBox *combo,
+static void style_changed_sig(GtkComboBox *combo,
struct _stylesheetwindow *s)
{
int n;
+ GdkColor col;
n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
- s->cur_layout_element = s->ss->layout_elements[n];
+ s->cur_style = s->ss->styles[n];
+ /* FIXME: Handle default style */
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->margin_left),
- s->cur_layout_element->margin_left);
+ s->cur_style->margin_left);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->margin_right),
- s->cur_layout_element->margin_right);
+ s->cur_style->margin_right);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->margin_bottom),
- s->cur_layout_element->margin_bottom);
+ s->cur_style->margin_bottom);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->margin_top),
- s->cur_layout_element->margin_top);
+ s->cur_style->margin_top);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->offset_x),
- s->cur_layout_element->offset_x);
+ s->cur_style->offset_x);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->offset_y),
- s->cur_layout_element->offset_y);
+ s->cur_style->offset_y);
gtk_combo_box_set_active(GTK_COMBO_BOX(s->halign),
- s->cur_layout_element->halign);
+ s->cur_style->halign);
gtk_combo_box_set_active(GTK_COMBO_BOX(s->valign),
- s->cur_layout_element->valign);
+ s->cur_style->valign);
gtk_widget_set_sensitive(s->max_width,
- s->cur_layout_element->use_max_width);
+ s->cur_style->use_max_width);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s->max_width),
- s->cur_layout_element->max_width);
+ s->cur_style->max_width);
+
+ n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
+ s->cur_style = s->ss->styles[n];
+
+ gtk_font_button_set_font_name(GTK_FONT_BUTTON(s->text_font),
+ s->cur_style->font);
+
+ gdk_color_parse(s->cur_style->colour, &col);
+ gtk_color_button_set_color(GTK_COLOR_BUTTON(s->text_colour), &col);
}
@@ -307,13 +237,13 @@ static void do_layout(struct _stylesheetwindow *s, GtkWidget *b)
gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
combo = gtk_combo_box_new_text();
- for ( i=0; i<s->ss->n_layout_elements; i++ ) {
+ for ( i=0; i<s->ss->n_styles; i++ ) {
gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
- s->ss->layout_elements[i]->name);
+ s->ss->styles[i]->name);
}
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
g_signal_connect(G_OBJECT(combo), "changed",
- G_CALLBACK(layout_changed_sig), s);
+ G_CALLBACK(style_changed_sig), s);
gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0);
line = gtk_hseparator_new();
@@ -428,8 +358,34 @@ static void do_layout(struct _stylesheetwindow *s, GtkWidget *b)
g_signal_connect(G_OBJECT(s->max_width), "value-changed",
G_CALLBACK(max_changed_sig), s);
+ /* Font/colour stuff */
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5.0);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5.0);
+
+ label = gtk_label_new("Font:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
+ s->text_font = gtk_font_button_new_with_font("Sans 12");
+ box = gtk_hbox_new(FALSE, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), box, 1, 2, 0, 1);
+ gtk_box_pack_start(GTK_BOX(box), s->text_font, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(s->text_font), "font-set",
+ G_CALLBACK(text_font_set_sig), s);
+
+ label = gtk_label_new("Colour:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
+ s->text_colour = gtk_color_button_new();
+ box = gtk_hbox_new(FALSE, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), box, 1, 2, 1, 2);
+ gtk_box_pack_start(GTK_BOX(box), s->text_colour, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(s->text_colour), "color-set",
+ G_CALLBACK(text_colour_set_sig), s);
+
/* Force first update */
- layout_changed_sig(GTK_COMBO_BOX(combo), s);
+ style_changed_sig(GTK_COMBO_BOX(combo), s);
}
@@ -442,115 +398,85 @@ static gint destroy_stylesheet_sig(GtkWidget *w, struct _stylesheetwindow *s)
}
-static void add_text_style(StyleSheet *ss, struct text_style *st)
-{
- int n = ss->n_text_styles;
- ss->text_styles = realloc(ss->text_styles,
- (n+1)*sizeof(st));
-
- ss->text_styles[n] = st;
-
- ss->n_text_styles = n+1;
-}
-
-
-static struct text_style *new_text_style(StyleSheet *ss, const char *name)
+static struct style *new_style(StyleSheet *ss, const char *name)
{
- struct text_style *st;
-
- st = malloc(sizeof(*st));
- if ( st == NULL ) return NULL;
-
- st->name = strdup(name);
- st->colour = strdup("#000000000000"); /* Black */
- st->alpha = 1.0;
-
- add_text_style(ss, st);
-
- return st;
-}
-
-
-static struct layout_element *new_layout_element(StyleSheet *ss,
- const char *name)
-{
- struct layout_element *ly;
+ struct style *sty;
int n;
+ struct style **styles_new;
- ly = malloc(sizeof(*ly));
- if ( ly == NULL ) return NULL;
-
- ly->name = strdup(name);
-
- n = ss->n_layout_elements;
- ss->layout_elements = realloc(ss->layout_elements, (n+1)*sizeof(ly));
- /* Yes, the size of the pointer */
+ sty = malloc(sizeof(*sty));
+ if ( sty == NULL ) return NULL;
- ss->layout_elements[n] = ly;
- ss->n_layout_elements = n+1;
+ n = ss->n_styles;
+ styles_new = realloc(ss->styles, (n+1)*sizeof(sty));
+ if ( styles_new == NULL ) {
+ free(sty);
+ return NULL;
+ }
+ ss->styles = styles_new;
+ ss->styles[n] = sty;
+ ss->n_styles = n+1;
- return ly;
+ return sty;
}
static void default_stylesheet(StyleSheet *ss)
{
- struct text_style *st;
- struct layout_element *ly;
-
- st = new_text_style(ss, "Slide title");
- st->font = strdup("Sans 40");
- ly = new_layout_element(ss, st->name);
- ly->text_style = st;
- ly->margin_left = 20.0;
- ly->margin_right = 20.0;
- ly->margin_top = 20.0;
- ly->margin_bottom = 20.0;
- ly->halign = J_CENTER;
- ly->valign = V_TOP;
- ly->offset_x = 0.0;
- ly->offset_y = 0.0; /* irrelevant */
-
- st = new_text_style(ss, "Presentation title");
- st->font = strdup("Sans 50");
- ly = new_layout_element(ss, st->name);
- ly->text_style = st;
- ly->margin_left = 20.0;
- ly->margin_right = 20.0;
- ly->margin_top = 20.0;
- ly->margin_bottom = 20.0;
- ly->halign = J_CENTER;
- ly->valign = V_CENTER;
- ly->offset_x = -200.0;
- ly->offset_y = +300.0;
-
- st = new_text_style(ss, "Presentation author");
- st->font = strdup("Sans 30");
- ly = new_layout_element(ss, st->name);
- ly->text_style = st;
- ly->margin_left = 20.0;
- ly->margin_right = 20.0;
- ly->margin_top = 20.0;
- ly->margin_bottom = 20.0;
- ly->halign = J_CENTER;
- ly->valign = V_CENTER;
- ly->offset_x = +200.0;
- ly->offset_y = -300.0;
-
- st = new_text_style(ss, "Running text");
- st->font = strdup("Sans 14");
-
- ly = new_layout_element(ss, "Slide content");
- ly->text_style = st;
- ly->margin_left = 20.0;
- ly->margin_right = 20.0;
- ly->margin_top = 20.0;
- ly->margin_bottom = 20.0;
- ly->halign = J_CENTER;
- ly->valign = V_CENTER;
- ly->offset_x = +200.0;
- ly->offset_y = -300.0;
-
+ struct style *sty;
+
+ /* Default style must be first */
+ sty = new_style(ss, "Default");
+ sty->font = strdup("Sans 18");
+ sty->colour = strdup("#000000000000"); /* Black */
+ sty->alpha = 1.0;
+ sty->margin_left = 20.0;
+ sty->margin_right = 20.0;
+ sty->margin_top = 20.0;
+ sty->margin_bottom = 20.0;
+ sty->halign = J_CENTER; /* Ignored */
+ sty->valign = V_CENTER; /* Ignored */
+ sty->offset_x = 0.0; /* Ignored */
+ sty->offset_y = 0.0; /* Ignored */
+
+ sty = new_style(ss, "Slide title");
+ sty->font = strdup("Sans 40");
+ sty->colour = strdup("#000000000000"); /* Black */
+ sty->alpha = 1.0;
+ sty->margin_left = 20.0;
+ sty->margin_right = 20.0;
+ sty->margin_top = 20.0;
+ sty->margin_bottom = 20.0;
+ sty->halign = J_CENTER;
+ sty->valign = V_TOP;
+ sty->offset_x = 0.0;
+ sty->offset_y = 0.0; /* irrelevant */
+
+ sty = new_style(ss, "Presentation title");
+ sty->font = strdup("Sans 50");
+ sty->colour = strdup("#000000000000"); /* Black */
+ sty->alpha = 1.0;
+ sty->margin_left = 20.0;
+ sty->margin_right = 20.0;
+ sty->margin_top = 20.0;
+ sty->margin_bottom = 20.0;
+ sty->halign = J_CENTER;
+ sty->valign = V_CENTER;
+ sty->offset_x = -200.0;
+ sty->offset_y = +300.0;
+
+ sty = new_style(ss, "Presentation author");
+ sty->font = strdup("Sans 30");
+ sty->colour = strdup("#000000000000"); /* Black */
+ sty->alpha = 1.0;
+ sty->margin_left = 20.0;
+ sty->margin_right = 20.0;
+ sty->margin_top = 20.0;
+ sty->margin_bottom = 20.0;
+ sty->halign = J_CENTER;
+ sty->valign = V_CENTER;
+ sty->offset_x = +200.0;
+ sty->offset_y = -300.0;
}
@@ -561,10 +487,8 @@ StyleSheet *new_stylesheet()
ss = calloc(1, sizeof(struct _stylesheet));
if ( ss == NULL ) return NULL;
- ss->n_text_styles = 0;
- ss->text_styles = NULL;
- ss->n_layout_elements = 0;
- ss->layout_elements = NULL;
+ ss->n_styles = 0;
+ ss->styles = NULL;
default_stylesheet(ss);
return ss;
@@ -622,8 +546,8 @@ StylesheetWindow *open_stylesheet(struct presentation *p)
s->p = p;
s->ss = p->ss;
- s->cur_text_style = NULL;
- s->cur_layout_element = NULL;
+ s->cur_style = NULL;
+ s->cur_style = NULL;
s->window = gtk_dialog_new_with_buttons("Stylesheet",
GTK_WINDOW(p->window), 0,
@@ -639,12 +563,6 @@ StylesheetWindow *open_stylesheet(struct presentation *p)
text_box = gtk_vbox_new(FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(text_box), 12);
gtk_notebook_append_page(GTK_NOTEBOOK(nb), text_box,
- gtk_label_new("Text styles"));
- do_text(s, text_box);
-
- text_box = gtk_vbox_new(FALSE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(text_box), 12);
- gtk_notebook_append_page(GTK_NOTEBOOK(nb), text_box,
gtk_label_new("Slide layout"));
do_layout(s, text_box);
diff --git a/src/stylesheet.h b/src/stylesheet.h
index 8f9733e..4b7f7fb 100644
--- a/src/stylesheet.h
+++ b/src/stylesheet.h
@@ -28,15 +28,6 @@
#endif
-struct text_style
-{
- char *name;
- char *font;
- char *colour;
- double alpha;
-};
-
-
enum justify
{
J_LEFT = 0,
@@ -53,10 +44,9 @@ enum vert_pos
};
-struct layout_element
+struct style
{
char *name;
- struct text_style *text_style;
double margin_left;
double margin_right;
@@ -70,22 +60,19 @@ struct layout_element
double offset_x;
double offset_y;
+
+ char *font;
+ char *colour;
+ double alpha;
};
struct _stylesheet
{
- /* Slide layout */
- struct layout_element **layout_elements;
- int n_layout_elements;
-
- /* Normal text styles */
- struct text_style **text_styles;
- int n_text_styles;
+ struct style **styles;
+ int n_styles;
/* Background stuff */
-
- /* Image styles */
};
diff --git a/src/tool_text.c b/src/tool_text.c
new file mode 100644
index 0000000..9419a12
--- /dev/null
+++ b/src/tool_text.c
@@ -0,0 +1,203 @@
+/*
+ * tool_text.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 "presentation.h"
+#include "objects.h"
+#include "mainwindow.h"
+
+
+struct object *add_text_object(struct slide *s, double x, double y,
+ struct style *sty)
+{
+ struct object *new;
+
+ new = new_object(TEXT, sty);
+
+ new->x = x; new->y = y;
+ new->bb_width = 10.0;
+ new->bb_height = 40.0;
+ new->text = malloc(1);
+ new->text[0] = '\0';
+ new->text_len = 1;
+ new->insertion_point = 0;
+ new->layout = NULL;
+ new->fontdesc = NULL;
+
+ if ( add_object_to_slide(s, new) ) {
+ free_object(new);
+ return NULL;
+ }
+ s->object_seq++;
+
+ return new;
+}
+
+
+void insert_text(struct object *o, char *t)
+{
+ char *tmp;
+ size_t tlen, olen;
+ int i;
+
+ assert(o->type == TEXT);
+ tlen = strlen(t);
+ olen = strlen(o->text);
+
+ if ( tlen + olen + 1 > o->text_len ) {
+
+ char *try;
+
+ try = realloc(o->text, o->text_len + tlen + 64);
+ if ( try == NULL ) return; /* Failed to insert */
+ o->text = try;
+ o->text_len += 64;
+ o->text_len += tlen;
+
+ }
+
+ tmp = malloc(o->text_len);
+ if ( tmp == NULL ) return;
+
+ for ( i=0; i<o->insertion_point; i++ ) {
+ tmp[i] = o->text[i];
+ }
+ for ( i=0; i<tlen; i++ ) {
+ tmp[i+o->insertion_point] = t[i];
+ }
+ for ( i=0; i<olen-o->insertion_point; i++ ) {
+ tmp[i+o->insertion_point+tlen] = o->text[i+o->insertion_point];
+ }
+ tmp[olen+tlen] = '\0';
+ memcpy(o->text, tmp, o->text_len);
+ free(tmp);
+
+ o->insertion_point += tlen;
+ o->parent->object_seq++;
+ o->empty = 0;
+}
+
+
+void set_text_style(struct object *o, struct style *sty)
+{
+ assert(o->type == TEXT);
+ o->style = sty;
+ o->parent->object_seq++;
+}
+
+
+static int find_prev_index(const char *t, int p)
+{
+ int i, nback;
+
+ if ( p == 0 ) return 0;
+
+ if ( !(t[p-1] & 0x80) ) {
+ nback = 1;
+ } else {
+ nback = 0;
+ for ( i=1; i<=6; i++ ) {
+ if ( p-i == 0 ) return 0;
+ if ( !(t[p-i] & 0xC0) ) nback++;
+ }
+ }
+
+ return p - nback;
+}
+
+
+static int find_next_index(const char *t, int p)
+{
+ int i, nfor;
+
+ if ( t[p] == '\0' ) return p;
+
+ if ( !(t[p+1] & 0x80) ) {
+ nfor = 1;
+ } else {
+ nfor = 0;
+ for ( i=1; i<=6; i++ ) {
+ if ( t[p+i] == '\0' ) return p+i;
+ if ( !(t[p+i] & 0xC0) ) nfor++;
+ }
+ }
+
+ return p + nfor;
+}
+
+
+void handle_text_backspace(struct object *o)
+{
+ int prev_index;
+
+ assert(o->type == TEXT);
+
+ if ( o->insertion_point == 0 ) return; /* Nothing to delete */
+
+ prev_index = find_prev_index(o->text, o->insertion_point);
+
+ memmove(o->text+prev_index, o->text+o->insertion_point,
+ o->text_len-o->insertion_point);
+
+ o->insertion_point = prev_index;
+
+ if ( strlen(o->text) == 0 ) o->empty = 1;
+
+ o->parent->object_seq++;
+}
+
+
+void move_cursor_left(struct object *o)
+{
+ o->insertion_point = find_prev_index(o->text, o->insertion_point);
+}
+
+
+void move_cursor_right(struct object *o)
+{
+ o->insertion_point = find_next_index(o->text, o->insertion_point);
+}
+
+
+void position_caret(struct object *o, double x, double y)
+{
+ int idx, trail;
+ int xp, yp;
+ gboolean v;
+
+ assert(o->type == TEXT);
+
+ xp = (x - o->x)*PANGO_SCALE;
+ yp = (y - o->y)*PANGO_SCALE;
+
+ v = pango_layout_xy_to_index(o->layout, xp, yp, &idx, &trail);
+
+ o->insertion_point = idx+trail;
+}
diff --git a/src/tool_text.h b/src/tool_text.h
new file mode 100644
index 0000000..cd190ae
--- /dev/null
+++ b/src/tool_text.h
@@ -0,0 +1,39 @@
+/*
+ * tool_text.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_TEXT_H
+#define TOOL_TEXT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+extern struct object *add_text_object(struct slide *s, double x, double y,
+ struct style *sty);
+extern void insert_text(struct object *o, char *t);
+extern void handle_text_backspace(struct object *o);
+extern void move_cursor_left(struct object *o);
+extern void move_cursor_right(struct object *o);
+extern void position_caret(struct object *o, double x, double y);
+
+
+#endif /* TOOL_TEXT_H */