写了两个 elisp 函数
GLib 学习笔记(未完成)

矩形选择

Garfileo posted @ 2011年1月03日 17:35 in 业余程序猿的足迹 with tags Cairo gtk+ gtkglext OpenGL , 5264 阅读

本来是灵机一动,考虑在 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


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter