diff options
Diffstat (limited to 'src/gtk-ink.c')
-rw-r--r-- | src/gtk-ink.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/gtk-ink.c b/src/gtk-ink.c new file mode 100644 index 0000000..793911d --- /dev/null +++ b/src/gtk-ink.c @@ -0,0 +1,297 @@ +/* + * gtk-ink.c + * + * GTK widget to display and collect Ink + * + * (c) 2002-2005 Thomas White <taw27@srcf.ucam.org> + * Part of TuxMessenger - GTK+-based MSN Messenger client + * + * This package 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; version 2 dated June, 1991. + * + * This package 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 package; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <math.h> +#include <libgnomecanvas/libgnomecanvas.h> + +#include "gtk-ink.h" +#include "ink.h" + +#define PAPER_WIDTH 640 +#define PAPER_HEIGHT 480 + +static GtkObjectClass *parent_class = NULL; + +static void gtk_ink_draw_point(GtkInk *gtk_ink, GnomeCanvasGroup *root, InkPoint *prev_point, InkPoint *new_point) { + + if ( prev_point == NULL ) { + gnome_canvas_item_new(root, gnome_canvas_ellipse_get_type(), "fill-color-gdk", gtk_ink->fgcolour, "x1", new_point->x-1, "y1", new_point->y-1, "x2", new_point->x+1, "y2", new_point->y+1, NULL); + } else { + + GnomeCanvasPoints *points; + gdouble width; + gdouble delta; + + points = gnome_canvas_points_new(2); + points->coords[0] = prev_point->x; + points->coords[1] = prev_point->y; + points->coords[2] = new_point->x; + points->coords[3] = new_point->y; + + delta = sqrt((prev_point->x - new_point->x)*(prev_point->x - new_point->x) + (prev_point->y - new_point->y)*(prev_point->y - new_point->y)); + + /* Calibrate 'feel' here. */ + width = (15-delta)/6.5; + if ( width < 0 ) { + width = 0; + } + + gnome_canvas_item_new(root, gnome_canvas_line_get_type(), "fill-color-gdk", gtk_ink->fgcolour, "points", points, "width-units", width, NULL); + } + +} + +gboolean gtk_ink_realize(GtkWidget *widget, GtkInk *gtk_ink) { + + InkStroke *stroke; + GnomeCanvasGroup *root; + + GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); + root = gnome_canvas_root(GNOME_CANVAS(gtk_ink)); + + /* Draw the (initial) pattern. */ + stroke = gtk_ink->ink->strokes; + while ( stroke != NULL ) { + + InkPoint *point; + point = stroke->points; + + while ( point != NULL ) { + + gtk_ink_draw_point(gtk_ink, root, point->prev, point); + point = point->next; + + } + stroke = stroke->next; + } + + return FALSE; + +} + +gboolean gtk_ink_expose_event(GtkWidget *widget, GdkEventExpose *event, GtkInk *gtk_ink) { + + /* Draw the border. */ + gtk_paint_shadow(widget->style, ((GtkLayout *)gtk_ink)->bin_window, widget->state, GTK_SHADOW_IN, &event->area, widget, NULL, 0, 0, gtk_ink->width, gtk_ink->height); + + return FALSE; + +} + +static void gtk_ink_size_allocate(GtkWidget *widget, GtkAllocation *allocation, GtkInk *gtk_ink) { + + gtk_ink->width = allocation->width; + gtk_ink->height = allocation->height; + gnome_canvas_set_scroll_region(GNOME_CANVAS(gtk_ink), 0, 0, allocation->width, allocation->height); + + /* Sort the background out. */ + if ( (gtk_ink->width > gtk_ink->x_bg_drawn * PAPER_WIDTH) || (gtk_ink->height > gtk_ink->y_bg_drawn * PAPER_HEIGHT) ) { + + int x, y; + GnomeCanvasGroup *root; + + root = gnome_canvas_root(GNOME_CANVAS(gtk_ink)); + + for ( x=gtk_ink->x_bg_drawn; x<=gtk_ink->width/PAPER_WIDTH; x++ ) { + for ( y=0; y<=gtk_ink->height/PAPER_HEIGHT; y++ ) { + if ( gtk_ink->bgpixbuf == NULL ) { + gnome_canvas_item_lower_to_bottom(gnome_canvas_item_new(root, gnome_canvas_rect_get_type(), "fill-color-gdk", gtk_ink->bgcolour, "x1", (gdouble)x*PAPER_WIDTH, "y1", (gdouble)y*PAPER_HEIGHT, "x2", (gdouble)(x+1)*PAPER_WIDTH, "y2", (gdouble)(y+1)*PAPER_HEIGHT, NULL)); + } else { + gnome_canvas_item_lower_to_bottom(gnome_canvas_item_new(root, gnome_canvas_pixbuf_get_type(), "pixbuf", gtk_ink->bgpixbuf, "x", (gdouble)x*PAPER_WIDTH, "y", (gdouble)y*PAPER_HEIGHT, "x-in-pixels", TRUE, "y-in-pixels", TRUE, "width-set", FALSE, "height-set", FALSE, NULL)); + } + } + } + gtk_ink->x_bg_drawn = (gtk_ink->width/PAPER_WIDTH)+1; + + for ( x=0; x<gtk_ink->width/PAPER_WIDTH; x++ ) { + for ( y=gtk_ink->y_bg_drawn; y<=gtk_ink->height/PAPER_HEIGHT; y++ ) { + if ( gtk_ink->bgpixbuf == NULL ) { + gnome_canvas_item_lower_to_bottom(gnome_canvas_item_new(root, gnome_canvas_rect_get_type(), "fill-color-gdk", gtk_ink->bgcolour, "x1", (gdouble)x*PAPER_WIDTH, "y1", (gdouble)y*PAPER_HEIGHT, "x2", (gdouble)(x+1)*PAPER_WIDTH, "y2", (gdouble)(y+1)*PAPER_HEIGHT, NULL)); + } else { + gnome_canvas_item_lower_to_bottom(gnome_canvas_item_new(root, gnome_canvas_pixbuf_get_type(), "pixbuf", gtk_ink->bgpixbuf, "x", (gdouble)x*PAPER_WIDTH, "y", (gdouble)y*PAPER_HEIGHT, "x-in-pixels", TRUE, "y-in-pixels", TRUE, "width-set", FALSE, "height-set", FALSE, NULL)); + } + } + } + gtk_ink->y_bg_drawn = (gtk_ink->height/PAPER_HEIGHT)+1; + + } + +} + +static void gtk_ink_add_point_and_draw(GtkInk *gtk_ink, double x, double y) { + + InkStroke *stroke; + InkPoint *prev_point; + InkPoint *new_point; + + stroke = ink_stroke_get_last(gtk_ink->ink); + prev_point = ink_point_get_last(stroke); + new_point = ink_point_add(stroke, x, y); + + gtk_ink_draw_point(gtk_ink, gnome_canvas_root(GNOME_CANVAS(gtk_ink)), prev_point, new_point); + +} + +static gboolean gtk_ink_button_release(GtkWidget *widget, GdkEventButton *event, GtkInk *gtk_ink) { + gtk_ink->drawing = FALSE; + return TRUE; +} + +static gboolean gtk_ink_button_press(GtkWidget *widget, GdkEventButton *event, GtkInk *gtk_ink) { + + ink_stroke_new(gtk_ink->ink); + gtk_ink_add_point_and_draw(gtk_ink, event->x, event->y); + gtk_ink->drawing = TRUE; + + /* Grab focus */ + if ( !GTK_WIDGET_HAS_DEFAULT(gtk_ink) ) { + gtk_widget_grab_default(GTK_WIDGET(gtk_ink)); + } + if ( !GTK_WIDGET_HAS_FOCUS(gtk_ink) ) { + gtk_widget_grab_focus(GTK_WIDGET(gtk_ink)); + } + + return TRUE; /* Claim it. */ + +} + +static gboolean gtk_ink_motion(GtkWidget *widget, GdkEventMotion *event, GtkInk *gtk_ink) { + + if ( gtk_ink->drawing ) { + gtk_ink_add_point_and_draw(gtk_ink, event->x, event->y); + return TRUE; + } + + return FALSE; + +} + +static void gtk_ink_destroy(GtkObject *gtk_ink) { + + /* GdkColors automagically freed. */ + parent_class->destroy(gtk_ink); + +} + +GtkWidget *gtk_ink_new(GtkInkFlags flags, Ink *ink, GdkColor *fgcolour, GdkColor *bgcolour) { + + GtkInk *gtk_ink; + + gtk_ink = GTK_INK(gtk_type_new(gtk_ink_get_type())); + + gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(gtk_ink), 1); + + gtk_signal_connect_after(GTK_OBJECT(gtk_ink), "expose_event", GTK_SIGNAL_FUNC(gtk_ink_expose_event), gtk_ink); + gtk_signal_connect(GTK_OBJECT(gtk_ink), "size_allocate", GTK_SIGNAL_FUNC(gtk_ink_size_allocate), gtk_ink); + gtk_signal_connect(GTK_OBJECT(gtk_ink), "realize", GTK_SIGNAL_FUNC(gtk_ink_realize), gtk_ink); + + if ( flags & GTK_INK_FLAG_EDITABLE ) { + gtk_signal_connect(GTK_OBJECT(gtk_ink), "button-press-event", GTK_SIGNAL_FUNC(gtk_ink_button_press), gtk_ink); + gtk_signal_connect(GTK_OBJECT(gtk_ink), "button-release-event", GTK_SIGNAL_FUNC(gtk_ink_button_release), gtk_ink); + gtk_signal_connect(GTK_OBJECT(gtk_ink), "motion-notify-event", GTK_SIGNAL_FUNC(gtk_ink_motion), gtk_ink); + gtk_widget_add_events(GTK_WIDGET(gtk_ink), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK); + } + g_object_set(G_OBJECT(gtk_ink), "can-focus", TRUE, "can-default", TRUE, NULL); + + /* Set up properties. */ + gtk_ink->bgcolour = gdk_color_copy(bgcolour); + gtk_ink->fgcolour = gdk_color_copy(fgcolour); + gtk_ink->flags = flags; + gtk_ink->ink = ink; + gtk_ink->x_bg_drawn = 0; + gtk_ink->y_bg_drawn = 0; + gtk_ink->drawing = FALSE; + + if ( flags & GTK_INK_FLAG_PAPER ) { + gtk_ink->bgpixbuf = gdk_pixbuf_new_from_file("/usr/local/share/tuxmessenger/paper.png", NULL); + } else { + gtk_ink->bgpixbuf = NULL; + } + + return GTK_WIDGET(gtk_ink); + +} + +static GObject *gtk_ink_constructor(GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { + + GtkInkClass *class; + GObjectClass *p_class; + GObject *obj; + + class = GTK_INK_CLASS(g_type_class_peek(gtk_ink_get_type())); + p_class = G_OBJECT_CLASS(g_type_class_peek_parent(class)); + + obj = p_class->constructor(type, n_construct_properties, construct_properties); + g_object_set(obj, "aa", TRUE, NULL); + + return obj; + +} + +static void gtk_ink_class_init(GtkInkClass *class) { + + GtkObjectClass *object_class; + GObjectClass *g_object_class; + + object_class = (GtkObjectClass *) class; + g_object_class = G_OBJECT_CLASS(class); + + object_class->destroy = gtk_ink_destroy; + g_object_class->constructor = gtk_ink_constructor; + + parent_class = gtk_type_class(gnome_canvas_get_type()); + +} + +static void gtk_ink_init(GtkInk *gtk_ink) { +} + +guint gtk_ink_get_type(void) { + + static guint gtk_ink_type = 0; + + if ( !gtk_ink_type ) { + + GtkTypeInfo gtk_ink_info = { + "GtkInk", + sizeof(GtkInk), + sizeof(GtkInkClass), + (GtkClassInitFunc) gtk_ink_class_init, + (GtkObjectInitFunc) gtk_ink_init, + NULL, + NULL, + (GtkClassInitFunc) NULL, + }; + gtk_ink_type = gtk_type_unique(gnome_canvas_get_type(), >k_ink_info); + + } + + return gtk_ink_type; + +} |