2006/03/11

gtk+-2.8なwidgetの中にcairoを使って絵を書こう(2)

さて step.2 expose イベント(隠れていたwindow が再描画される時)のシグナルハンドラとして時計の背景を描写する。ここのclock-ex1.cから始めるのが楽。gtk+-2.8が入っているから、コンパイルに必要なフラグは‘pkg-config --cflags gtk+-2.0‘、 リンクは‘pkg-config --libs gtk+-2.0‘ -lm でよい。ここで背景を描写するのはexpose シグナルハンドラとして呼ばれる関数 egg_clock_face_expose です。これは

static gboolean
egg_clock_face_expose (GtkWidget *clock, GdkEventExpose *event)
{
cairo_t *cr;

/* get a cairo_t */
cr = gdk_cairo_create (clock->window);

/*ここで絵を書く。*/
draw (clock, cr);

cairo_destroy (cr);

return FALSE;

}
これだけでいい。後は絵を書く関数 draw を作れば絵が書ける。
static void
draw (GtkWidget *clock, cairo_t *cr)
draw関数の定義はこれ。っと、元のサンプルはその前に高速化のために隠れた所だけを再描画するように、drawの前に
cairo_rectangle (cr,
event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_clip(cr);
を追加している。これは絵を書くだけならば必要ではない。

それでは始めに時計の背景として円を描く。draw関数に、

double x, y;/*中心座標*/
x = clock->allocation.x + clock->allocation.width / 2;
y = clock->allocation.y + clock->allocation.height / 2;
double radius;
radius = MIN (clock->allocation.width / 2,
clock->allocation.height / 2) - 5;
cairo_arc (cr, x, y, radius, 0, 2 * M_PI);

cairo_set_source_rgb (cr, 1, 1, 1);/*色の指定、白*/
cairo_fill_preserve (cr);/*円の中を白色で塗る。*/
cairo_set_source_rgb (cr, 0, 0, 0);/*黒*/
cairo_stroke (cr);/*円を描く*/
で書ける。
四角な時計がいいなら、
double x,y ;
x = clock->allocation.x + clock->allocation.width * 0.05;
y = clock->allocation.y + clock->allocation.height * 0.05 ;

cairo_rectangle( cr , x ,y ,clock->allocation.width*0.9,clock->allocation.height * 0.9 );
cairo_set_source_rgb( cr , 1, 1, 1);
cairo_fill_preserve (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_stroke (cr);

cairo で線を書くのは、ペンで描くようなイメージか(postscript言語に似ている。)。
まず、cairo_move_to でペンを持っていく場所(線の最初の点)を指定。(ペンを空中で持っていくようなイメージ。)次にcairo_line_to でペンを動かす目標を決める(線の最後の点)。んでcairo_strokeで実際に線を書く。(x0,y0)から (x1,y1)へ線を引くには、
cairo_move_to (cr,x0,y0);
cairo_line_to (cr,x1,y1);
cairo_stroke (cr);
となる。時計の細かい線の書きかたは元のページを見てね。



余談、expose_eventを追加するには、このクラスのinit関数の中で、

static void
egg_clock_face_class_init (EggClockFaceClass *class)
{
GtkWidgetClass *widget_class;

widget_class = GTK_WIDGET_CLASS (class);

widget_class->expose_event = egg_clock_face_expose;
}

とexpose_eventにegg_clock_face_exposeを追加したらよい。