網誌存檔

2010年11月16日 星期二

「轉貼」Cairo 圖形指南 (9) —— 透明

「等待」的演示

下面的示例,使用透明效果製作了一個「等待」狀態的演示,是通過繪製 8 條依次消隱淡出的線,模擬一條線的運動過程。像這樣的效果通常被用於通知用戶耐心地等待一個隱藏在屏幕之後漫長的任務的完成。在網上看視頻時,經常可以看到類似的「等待」。

#include
#include
#include

static gushort count = 0;

static gboolean
on_expose_event (GtkWidget * widget,
GdkEventExpose * event, gpointer data)
{
cairo_t *cr;

cr = gdk_cairo_create (widget->window);

static gdouble const trs[8][8] = {
{0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0},
{1.0, 0.0, 0.15, 0.30, 0.5, 0.65, 0.8, 0.9},
{0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65, 0.8},
{0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65},
{0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5},
{0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3},
{0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15},
{0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0,}
};


gint width, height;
gtk_window_get_size (GTK_WINDOW (widget), &width, &height);

cairo_translate (cr, width / 2, height / 2);

gint i = 0;
for (i = 0; i < 8; i++) {
cairo_set_line_width (cr, 3);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_source_rgba (cr, 0, 0, 0, trs[count % 8][i]);

cairo_move_to (cr, 0.0, -10.0);
cairo_line_to (cr, 0.0, -40.0);
cairo_rotate (cr, M_PI / 4);

cairo_stroke (cr);
}

cairo_destroy (cr);

return FALSE;
}

static gboolean
time_handler (GtkWidget * widget)
{
count += 1;
gtk_widget_queue_draw (widget);
return TRUE;
}

int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;

gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

g_signal_connect (G_OBJECT (window), "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);

gtk_window_set_position (GTK_WINDOW (window),
GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (window), 250, 150);

gtk_window_set_title (GTK_WINDOW (window), "waiting demo");

gtk_widget_set_app_paintable (window, TRUE);
gtk_widget_show_all (window);
g_timeout_add (100, (GSourceFunc) time_handler,
(gpointer) window);

gtk_main ();

return 0;
}

方法比較笨,就是繪製 8 條不同透明度的線。


static gdouble const trs[8][8] = {
{0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0},
{1.0, 0.0, 0.15, 0.30, 0.5, 0.65, 0.8, 0.9},
{0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65, 0.8},
{0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65},
{0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5},
{0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3},
{0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15},
{0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0,}
};

這 8 條線的透明度就是這樣被活生生地定義出來的,每一行表示一條線的透明度候選集。


cairo_set_line_width (cr, 3);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);

設置線寬與線帽。


cairo_set_source_rgba (cr, 0, 0, 0, trs[count % 8][i]);

每條線的透明度就是這樣活生生地變化出來的。


cairo_move_to (cr, 0.0, -10.0);
cairo_line_to (cr, 0.0, -40.0);
cairo_rotate (cr, M_PI / 4);

這裡有個從未講過的技巧,就是 cairo 的旋轉變換。每次都在前一次旋轉的基礎上繼續逆時針旋轉 $\frac{\pi}{4}$角度。這樣,8 次循環之後,恰好繞了一圈。


g_timeout_add (100, (GSourceFunc) time_handler, (gpointer) window);

又是計時器。


沒有留言:

張貼留言