矩形选择
本来是灵机一动,考虑在 gtkglext widget 上使用 cairo 在窗口中动态绘制一个矩形框表示所选的 OpenGL 三空间中的局部区域,然后将这个矩形框映射到 OpenGL 三维空间中得到三维选区,并将 OpenGL 的视景体调整为这个三维选区,从而实现 OpenGL 图形的放大效果。可惜,这个灵机一动没成功,cairo 所绘制的矩形框被 gtkglext 的双缓冲区里的图形淹没了。
尽管如此,我还是要将这个 cairo 效果拿出来展展,用于揭示虽然我一直都喜欢 gtk+,但是这实际上是我第一个具有现实意义的 gtk+ 程序 :)

为了简单起见,程序写的很难看,还借用了当初我翻译的那个『cairo 图形指南』里的一份示例:
#include <gtk/gtk.h>
typedef struct _Rectangle Rectangle;
struct _Rectangle {
gdouble v1[2];
gdouble v2[2];
};
Rectangle rect = { {0.0, 0.0}, {0.0, 0.0} };
static gboolean
expose (GtkWidget * widget, cairo_t *cr, gpointer data)
{
/* 这段代码就是为了在窗口区域绘制一些文字,主要是为了显摆矩形选框的 */
cairo_set_source_rgb (cr, 0.1, 0.1, 0.1);
cairo_select_font_face (cr, "Bitstream Vera Sans",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, 13);
cairo_move_to (cr, 20, 30);
cairo_show_text (cr, "Most relationships seem so transitory");
cairo_move_to (cr, 20, 60);
cairo_show_text (cr, "They're all good but not the permanent one");
cairo_move_to (cr, 20, 120);
cairo_show_text (cr, "Who doesn't long for someone to hold");
cairo_move_to (cr, 20, 150);
cairo_show_text (cr,
"Who knows how to love you without being told");
cairo_move_to (cr, 20, 180);
cairo_show_text (cr, "Somebody tell me why I'm on my own");
cairo_move_to (cr, 20, 210);
cairo_show_text (cr, "If there's a soulmate for everyone");
/* 绘制矩形选框 */
cairo_rectangle (cr, rect.v1[0], rect.v1[1],
rect.v2[0] - rect.v1[0], rect.v2[1] - rect.v1[1]);
cairo_set_line_width (cr, 2);
cairo_set_source_rgba (cr, 0.6, 0.4, 0.2, 1.0);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_stroke_preserve (cr);
cairo_set_source_rgba (cr, 0.6, 0.4, 0.2, 0.5);
cairo_fill (cr);
return FALSE;
}
static gboolean
clicked (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
{
if (event->button == 1) {
rect.v1[0] = event->x;
rect.v1[1] = event->y;
}
return FALSE;
}
static gboolean
motion (GtkWidget * widget, GdkEventMotion * event, gpointer data)
{
if (event->state & GDK_BUTTON1_MASK) {
rect.v2[0] = event->x;
rect.v2[1] = event->y;
gtk_widget_queue_draw (widget);
}
return FALSE;
}
static gboolean
release (GtkWidget * widget, GdkEventMotion * event, gpointer data)
{
rect.v1[0] = rect.v1[1] = rect.v2[0] = rect.v2[1] = 0.0;
gtk_widget_queue_draw (widget);
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_add_events (window,
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_SCROLL_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect (window, "draw", G_CALLBACK (expose), NULL);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (window, "button-press-event",
G_CALLBACK (clicked), NULL);
g_signal_connect (window, "motion_notify_event",
G_CALLBACK (motion), NULL);
g_signal_connect (window, "button-release-event",
G_CALLBACK (release), NULL);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_window_set_title (GTK_WINDOW (window), "test");
gtk_window_set_default_size (GTK_WINDOW (window), 420, 250);
gtk_widget_set_app_paintable (window, TRUE);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
用这个命令可以编译这个程序(前提是安装了 gcc 和 gtk+):
$ gcc `pkg-config --cflags --libs gtk+-3.0` test.c -o test
注意,这里我使用的是 gtk+ 3.0。所有的窗口图形绘制工作均交给了 cairo。
由于 cairo 不给力,所以我不得不暗自将 gtk+ 窗口中的鼠标位置映射到 gtkglext 所营造的 OpenGL 场景中,从而构造一个三维平面来实现与上例相似的效果 \footnote{代码很繁琐,不贴了,也别向我要 :) }:


转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com
评论 (0)