/* * gtk-ink.c * * GTK widget to display and collect Ink * * (c) 2002-2005 Thomas White * 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 #endif #include #include #include #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; xwidth/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; }