#include #include static GtkWidget *main_window = NULL; enum shape_type { SHAPE_TRIANGLE = 0, SHAPE_RECTANGLE, SHAPE_STAR, SHAPE_FLOWER, MAX_SHAPE_TYPE }; struct shape_data { gint x; gint y; gint color; gint scale; enum shape_type shape; } shape_data; static GList *shape_list = NULL; static GdkColor palette[] = { { 0, 0x0000, 0x0000, 0xFFFF }, { 0, 0x0000, 0xFFFF, 0x0000 }, { 0, 0x0000, 0xC000, 0xFFFF }, { 0, 0x8000, 0x0000, 0xFFFF }, { 0, 0xFFFF, 0xFFFF, 0x0000 }, { 0, 0xFFFF, 0x0000, 0xC000 }, { 0, 0xFFFF, 0x0000, 0x0000 }, { 0, 0xFFFF, 0xA000, 0x0000 } }; static const gint MAX_PALETTE = (sizeof(palette) / sizeof(palette[0])); static gint shape_scales[10] = { 20, 25, 30, 35, 40, 45, 50, 55, 60, 65 }; static gint scale = 0; void drawing_area_destroy(GtkObject *object, gpointer user_data) { GdkGC *gc = (GdkGC *)user_data; g_object_unref(gc); } void change_color(GdkGC *gc, GdkColor *color) { gdk_colormap_alloc_color(gdk_colormap_get_system(), color, FALSE, TRUE); gdk_gc_set_foreground(gc, color); } void change_line_width(GdkGC *gc, gint line_width) { gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); } void draw_triangle(GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint color, gint scale) { GdkPoint points[3]; points[0].x = x; points[0].y = y - shape_scales[scale]; points[1].x = x - shape_scales[scale] * 0.866025; points[1].y = y + shape_scales[scale] * 0.5; points[2].x = x + shape_scales[scale] * 0.866025; points[2].y = y + shape_scales[scale] * 0.5; change_line_width(gc, scale / 2 + 1); change_color(gc, &palette[color]); gdk_draw_polygon(drawable, gc, FALSE, points, 3); } void draw_rectangle(GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint color, gint scale) { gint size = shape_scales[scale] * 1.5; change_line_width(gc, scale / 2 + 1); change_color(gc, &palette[color]); gdk_draw_rectangle(drawable, gc, FALSE, x - size / 2, y - size / 2, size, size); } void draw_star(GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint color, gint scale) { GdkPoint points[5]; points[0].x = x; points[0].y = y - shape_scales[scale]; points[1].x = x + shape_scales[scale] * 0.587785; points[1].y = y + shape_scales[scale] * 0.809017; points[2].x = x - shape_scales[scale] * 0.951057; points[2].y = y - shape_scales[scale] * 0.309017; points[3].x = x + shape_scales[scale] * 0.951057; points[3].y = y - shape_scales[scale] * 0.309017; points[4].x = x - shape_scales[scale] * 0.587785; points[4].y = y + shape_scales[scale] * 0.809017; change_line_width(gc, scale / 2 + 1); change_color(gc, &palette[color]); gdk_draw_polygon(drawable, gc, FALSE, points, 5); } void draw_flower(GdkDrawable *drawable, GdkGC *gc, gint x, gint y, gint color, gint scale) { int i; GdkPoint points[8]; gint r1; gint r2; points[0].x = x; points[0].y = y - shape_scales[scale]; points[1].x = x - shape_scales[scale] * 0.707107; points[1].y = y - shape_scales[scale] * 0.707107; points[2].x = x - shape_scales[scale]; points[2].y = y; points[3].x = x - shape_scales[scale] * 0.707107; points[3].y = y + shape_scales[scale] * 0.707107; points[4].x = x; points[4].y = y + shape_scales[scale]; points[5].x = x + shape_scales[scale] * 0.707107; points[5].y = y + shape_scales[scale] * 0.707107; points[6].x = x + shape_scales[scale]; points[6].y = y; points[7].x = x + shape_scales[scale] * 0.707107; points[7].y = y - shape_scales[scale] * 0.707107; r1 = shape_scales[scale]; r2 = shape_scales[scale] * 0.4; change_line_width(gc, scale / 2 + 1); change_color(gc, &palette[color]); gdk_draw_arc(drawable, gc, FALSE, x - r1 / 2, y - r1 / 2, r1, r1, 0, 360 * 64); change_color(gc, &palette[(color + MAX_PALETTE / 2) % MAX_PALETTE]); for (i = 0; i < 8; i++) { gdk_draw_arc(drawable, gc, FALSE, points[i].x - r2 / 2, points[i].y - r2 / 2, r2, r2, 0, 360 * 64); } } void draw_shape(GdkDrawable *drawable, GdkGC *gc, const struct shape_data *shape) { switch (shape->shape) { case SHAPE_TRIANGLE: draw_triangle(drawable, gc, shape->x, shape->y, shape->color, shape->scale); break; case SHAPE_RECTANGLE: draw_rectangle(drawable, gc, shape->x, shape->y, shape->color, shape->scale); break; case SHAPE_STAR: draw_star(drawable, gc, shape->x, shape->y, shape->color, shape->scale); break; case SHAPE_FLOWER: draw_flower(drawable, gc, shape->x, shape->y, shape->color, shape->scale); break; } } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { GdkGC *gc = (GdkGC *)user_data; GList *cur; if (event->count != 0) { return TRUE; } for (cur = g_list_first(shape_list); cur != NULL; cur = g_list_next(cur)) { draw_shape(widget->window, gc, (struct shape_data *)cur->data); } return TRUE; } gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { GdkGC *gc = (GdkGC *)user_data; struct shape_data *shape; shape = g_new(struct shape_data, 1); shape->x = (gint)event->x; shape->y = (gint)event->y; shape->color = g_random_int_range(0, MAX_PALETTE); shape->scale = scale; shape->shape = g_random_int_range(0, MAX_SHAPE_TYPE); shape_list = g_list_append(shape_list, shape); draw_shape(widget->window, gc, shape); } gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { switch (event->keyval) { case GDK_0: case GDK_KP_0: scale = 0; break; case GDK_1: case GDK_KP_1: scale = 1; break; case GDK_2: case GDK_KP_2: scale = 2; break; case GDK_3: case GDK_KP_3: scale = 3; break; case GDK_4: case GDK_KP_4: scale = 4; break; case GDK_5: case GDK_KP_5: scale = 5; break; case GDK_6: case GDK_KP_6: scale = 6; break; case GDK_7: case GDK_KP_7: scale = 7; break; case GDK_8: case GDK_KP_8: scale = 8; break; case GDK_9: case GDK_KP_9: scale = 9; break; default: return FALSE; } return TRUE; } int main(int argc, char **argv) { GtkWidget *drawing_area; GdkGC *gc; gtk_init(&argc, &argv); main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(main_window), "GtkDrawingArea - test"); g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(gtk_main_quit), NULL); drawing_area = gtk_drawing_area_new(); gtk_widget_set_size_request(drawing_area, 400, 400); gtk_container_add(GTK_CONTAINER(main_window), drawing_area); gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK); GTK_WIDGET_SET_FLAGS(drawing_area, GTK_CAN_FOCUS); gtk_widget_show_all(main_window); gc = gdk_gc_new(drawing_area->window); change_line_width(gc, 1); g_signal_connect(G_OBJECT(drawing_area), "destroy", G_CALLBACK(drawing_area_destroy), gc); g_signal_connect(G_OBJECT(drawing_area), "expose-event", G_CALLBACK(expose_event), gc); g_signal_connect(G_OBJECT(drawing_area), "button-press-event", G_CALLBACK(button_press_event), gc); g_signal_connect(G_OBJECT(drawing_area), "key-press-event", G_CALLBACK(key_press_event), gc); gtk_main(); return 0; }