tests: Add testpicture test
Needs more fun, but I can add that later.
This commit is contained in:
@@ -67,6 +67,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
|
||||
testoffscreen \
|
||||
testoffscreenwindow \
|
||||
testorientable \
|
||||
testpicture \
|
||||
testprint \
|
||||
testrecentchooser \
|
||||
testrecentchoosermenu \
|
||||
@@ -167,6 +168,7 @@ testoffscreenwindow_DEPENDENCIES = $(TEST_DEPS)
|
||||
testappchooser_DEPENDENCIES = $(TEST_DEPS)
|
||||
testappchooserbutton_DEPENDENCIES = $(TEST_DEPS)
|
||||
testorientable_DEPENDENCIES = $(TEST_DEPS)
|
||||
testpicture_DEPENDENCIES = $(TEST_DEPS)
|
||||
testprint_DEPENDENCIES = $(TEST_DEPS)
|
||||
testrecentchooser_DEPENDENCIES = $(TEST_DEPS)
|
||||
testrecentchoosermenu_DEPENDENCIES = $(TEST_DEPS)
|
||||
@@ -249,6 +251,7 @@ testoffscreenwindow_LDADD = $(LDADDS)
|
||||
testappchooser_LDADD = $(LDADDS)
|
||||
testappchooserbutton_LDADD = $(LDADDS)
|
||||
testorientable_LDADD = $(LDADDS)
|
||||
testpicture_LDADD = $(LDADDS)
|
||||
testprint_LDADD = $(LDADDS)
|
||||
testrecentchooser_LDADD = $(LDADDS)
|
||||
testrecentchoosermenu_LDADD = $(LDADDS)
|
||||
|
||||
422
tests/testpicture.c
Normal file
422
tests/testpicture.c
Normal file
@@ -0,0 +1,422 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define SLOW_TYPE_INPUT_STREAM (slow_input_stream_get_type ())
|
||||
#define SLOW_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SLOW_TYPE_INPUT_STREAM, SlowInputStream))
|
||||
#define SLOW_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SLOW_TYPE_INPUT_STREAM, SlowInputStreamClass))
|
||||
#define SLOW_IS_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SLOW_TYPE_INPUT_STREAM))
|
||||
#define SLOW_IS_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SLOW_TYPE_INPUT_STREAM))
|
||||
#define SLOW_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SLOW_TYPE_INPUT_STREAM, SlowInputStreamClass))
|
||||
|
||||
typedef GFilterInputStream SlowInputStream;
|
||||
typedef GFilterInputStreamClass SlowInputStreamClass;
|
||||
G_DEFINE_TYPE (SlowInputStream, slow_input_stream, G_TYPE_FILTER_INPUT_STREAM)
|
||||
|
||||
static gssize
|
||||
slow_input_stream_read (GInputStream *stream,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gssize result;
|
||||
|
||||
count = MIN (count, 100);
|
||||
|
||||
result = g_input_stream_read (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (stream)),
|
||||
buffer,
|
||||
count,
|
||||
cancellable,
|
||||
error);
|
||||
|
||||
if (result > 0)
|
||||
g_usleep (result * G_USEC_PER_SEC / 500);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
slow_input_stream_close (GInputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_usleep (5 * G_USEC_PER_SEC);
|
||||
|
||||
return g_input_stream_close (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (stream)),
|
||||
cancellable,
|
||||
error);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
slow_input_stream_class_init (SlowInputStreamClass *klass)
|
||||
{
|
||||
GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (klass);
|
||||
|
||||
input_stream_class->read_fn = slow_input_stream_read;
|
||||
input_stream_class->close_fn = slow_input_stream_close;
|
||||
}
|
||||
|
||||
static void
|
||||
slow_input_stream_init (SlowInputStream *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static GInputStream *
|
||||
slow_input_stream_new (GInputStream *base_stream)
|
||||
{
|
||||
return g_object_new (slow_input_stream_get_type (), "base-stream", base_stream, NULL);
|
||||
}
|
||||
|
||||
typedef struct _Demo Demo;
|
||||
struct _Demo
|
||||
{
|
||||
const char *name;
|
||||
void (* create) (Demo *demo);
|
||||
GtkWidget *widget;
|
||||
GdkPicture *picture;
|
||||
GdkPicture *attached_picture;
|
||||
};
|
||||
|
||||
static void
|
||||
file_is_loaded_callback (GObject *object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
slowly_load_file (Demo *demo, GFile *file)
|
||||
{
|
||||
GInputStream *file_stream, *load_stream;
|
||||
|
||||
file_stream = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
|
||||
if (file_stream == NULL)
|
||||
return;
|
||||
load_stream = slow_input_stream_new (file_stream);
|
||||
gdk_picture_loader_load_from_stream_async (GDK_PICTURE_LOADER (demo->picture),
|
||||
load_stream,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
file_is_loaded_callback,
|
||||
demo);
|
||||
g_object_unref (file_stream);
|
||||
g_object_unref (load_stream);
|
||||
}
|
||||
|
||||
static void
|
||||
file_set_callback (GtkFileChooser *button,
|
||||
Demo *demo)
|
||||
{
|
||||
GFile *file = gtk_file_chooser_get_file (button);
|
||||
|
||||
if (file)
|
||||
slowly_load_file (demo, file);
|
||||
}
|
||||
|
||||
static void
|
||||
create_slowly_loading_image (Demo *demo)
|
||||
{
|
||||
GtkWidget *button, *image;
|
||||
GtkFileFilter *filter;
|
||||
GFile *default_file;
|
||||
|
||||
demo->widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
demo->picture = gdk_picture_loader_new ();
|
||||
|
||||
button = gtk_file_chooser_button_new ("Select file to slowly load",
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN);
|
||||
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (button), FALSE);
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_add_pixbuf_formats (filter);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (button), filter);
|
||||
default_file = g_file_new_for_path ("apple-red.png");
|
||||
gtk_file_chooser_set_file (GTK_FILE_CHOOSER (button),
|
||||
default_file, NULL);
|
||||
slowly_load_file (demo, default_file);
|
||||
g_object_unref (default_file);
|
||||
g_signal_connect (button,
|
||||
"file-set",
|
||||
G_CALLBACK (file_set_callback),
|
||||
demo);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (demo->widget), button, TRUE, TRUE, 0);
|
||||
|
||||
image = gtk_image_new_from_picture (demo->picture);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (demo->widget), image, TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
create_stock_picture (Demo *demo)
|
||||
{
|
||||
demo->widget = gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_BUTTON);
|
||||
gtk_widget_set_direction (demo->widget, GTK_TEXT_DIR_RTL);
|
||||
demo->picture = gtk_stock_picture_new (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_BUTTON);
|
||||
}
|
||||
|
||||
static void
|
||||
create_icon_set_picture (Demo *demo)
|
||||
{
|
||||
struct {
|
||||
const char *icon_name;
|
||||
GtkStateType state;
|
||||
} states[] = {
|
||||
{ GTK_STOCK_HOME, GTK_STATE_NORMAL },
|
||||
{ GTK_STOCK_APPLY, GTK_STATE_ACTIVE },
|
||||
{ GTK_STOCK_YES, GTK_STATE_PRELIGHT },
|
||||
{ GTK_STOCK_SELECT_ALL, GTK_STATE_SELECTED },
|
||||
{ GTK_STOCK_HELP, GTK_STATE_INSENSITIVE },
|
||||
{ GTK_STOCK_ABOUT, GTK_STATE_INCONSISTENT },
|
||||
{ GTK_STOCK_OK, GTK_STATE_FOCUSED }
|
||||
};
|
||||
GtkIconSet *set;
|
||||
GtkIconSource *source;
|
||||
guint i;
|
||||
|
||||
set = gtk_icon_set_new ();
|
||||
for (i = 0; i < G_N_ELEMENTS (states); i++)
|
||||
{
|
||||
source = gtk_icon_source_new ();
|
||||
gtk_icon_source_set_state (source, states[i].state);
|
||||
gtk_icon_source_set_state_wildcarded (source, FALSE);
|
||||
gtk_icon_source_set_icon_name (source, states[i].icon_name);
|
||||
gtk_icon_set_add_source (set, source);
|
||||
gtk_icon_source_free (source);
|
||||
}
|
||||
|
||||
demo->widget = gtk_label_new ("Shows a manually constructed icon set.\n"
|
||||
"It displays random stock icons fordifferent states.");
|
||||
|
||||
demo->picture = gtk_icon_set_picture_new (set, GTK_ICON_SIZE_BUTTON);
|
||||
|
||||
gtk_icon_set_unref (set);
|
||||
}
|
||||
|
||||
Demo demos[] = {
|
||||
{ "Slowly loading image", create_slowly_loading_image, NULL, NULL },
|
||||
{ "Another slowly loading image", create_slowly_loading_image, NULL, NULL },
|
||||
{ "Named theme icons", create_stock_picture, NULL, NULL },
|
||||
{ "Icon Set", create_icon_set_picture, NULL, NULL }
|
||||
};
|
||||
|
||||
static guint rotation = 0;
|
||||
static guint rotation_source = 0;
|
||||
|
||||
static void
|
||||
get_picture_offset (GtkWidget *widget,
|
||||
guint i,
|
||||
double *offset_x,
|
||||
double *offset_y)
|
||||
{
|
||||
double rx, ry;
|
||||
|
||||
rx = (gtk_widget_get_allocated_width (widget) - gdk_picture_get_width (demos[i].attached_picture)) / 2.0;
|
||||
ry = (gtk_widget_get_allocated_height (widget) - gdk_picture_get_height (demos[i].attached_picture)) / 2.0;
|
||||
|
||||
*offset_x = gtk_widget_get_allocated_width (widget) / 2.0
|
||||
+ rx * sin (2 * G_PI * i / G_N_ELEMENTS (demos) + (2 * G_PI * rotation / 360))
|
||||
- gdk_picture_get_width (demos[i].attached_picture) / 2.0;
|
||||
*offset_y = gtk_widget_get_allocated_height (widget) / 2.0
|
||||
+ ry * cos (2 * G_PI * i / G_N_ELEMENTS (demos) + (2 * G_PI * rotation / 360))
|
||||
- gdk_picture_get_height (demos[i].attached_picture) / 2.0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
draw_callback (GtkWidget *area,
|
||||
cairo_t *cr,
|
||||
gpointer unused)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (demos); i++)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
get_picture_offset (area, i, &x, &y);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_translate (cr, x, y);
|
||||
gdk_picture_draw (demos[i].attached_picture, cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define ROTATE_FPS 40
|
||||
#define ROTATE_SECONDS 3
|
||||
|
||||
static gboolean
|
||||
rotate_area (gpointer area)
|
||||
{
|
||||
rotation += 360 / ROTATE_SECONDS / ROTATE_FPS;
|
||||
rotation %= 360;
|
||||
|
||||
gtk_widget_queue_draw (area);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
rotation_toggled (GtkButton *button, GtkWidget *area)
|
||||
{
|
||||
if (rotation_source)
|
||||
{
|
||||
g_source_remove (rotation_source);
|
||||
rotation_source = 0;
|
||||
gtk_button_set_label (button, GTK_STOCK_MEDIA_PLAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotation_source = gdk_threads_add_timeout (1000 / ROTATE_FPS, rotate_area, area);
|
||||
gtk_button_set_label (button, GTK_STOCK_MEDIA_PAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
picture_changed (GdkPicture *picture, const cairo_region_t *region, GtkWidget *area)
|
||||
{
|
||||
cairo_region_t *copy;
|
||||
double x, y;
|
||||
int dx, dy;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (demos); i++)
|
||||
{
|
||||
if (demos[i].attached_picture == picture)
|
||||
break;
|
||||
}
|
||||
g_assert (i < G_N_ELEMENTS (demos));
|
||||
|
||||
get_picture_offset (area, i, &x, &y);
|
||||
copy = cairo_region_copy (region);
|
||||
cairo_region_translate (copy, floor (x), floor (y));
|
||||
gtk_widget_queue_draw_region (area, copy);
|
||||
dx = (floor (x) != ceil (x)) ? 1 : 0;
|
||||
dy = (floor (y) != ceil (y)) ? 1 : 0;
|
||||
if (dx || dy)
|
||||
{
|
||||
cairo_region_translate (copy, dx, dy);
|
||||
gtk_widget_queue_draw_region (area, copy);
|
||||
}
|
||||
cairo_region_destroy (copy);
|
||||
}
|
||||
|
||||
static void
|
||||
toggled_flag (GtkWidget *check, gpointer area)
|
||||
{
|
||||
int flag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (check), "flags"));
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)))
|
||||
gtk_widget_set_state_flags (area, flag, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (area, flag);
|
||||
}
|
||||
else
|
||||
gtk_widget_set_direction (area,
|
||||
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)) ? GTK_TEXT_DIR_RTL :
|
||||
GTK_TEXT_DIR_LTR);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_optionsview (GtkWidget *area)
|
||||
{
|
||||
struct {
|
||||
GtkStateFlags flags;
|
||||
const char * text;
|
||||
} options[] = {
|
||||
{ 0, "right-to-left" },
|
||||
{ GTK_STATE_FLAG_ACTIVE, "active" },
|
||||
{ GTK_STATE_FLAG_PRELIGHT, "prelight" },
|
||||
{ GTK_STATE_FLAG_SELECTED, "selected" },
|
||||
{ GTK_STATE_FLAG_INSENSITIVE, "insensitive" },
|
||||
{ GTK_STATE_FLAG_INCONSISTENT, "inconsistent" },
|
||||
{ GTK_STATE_FLAG_FOCUSED, "focused" }
|
||||
};
|
||||
GtkWidget *box, *check;
|
||||
guint i;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
for (i = 0; i < G_N_ELEMENTS (options); i++)
|
||||
{
|
||||
check = gtk_check_button_new_with_label (options[i].text);
|
||||
if (options[i].flags)
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check),
|
||||
gtk_widget_get_state_flags (area) & options[i].flags);
|
||||
else
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check),
|
||||
gtk_widget_get_direction (area) == GTK_TEXT_DIR_RTL);
|
||||
g_object_set_data (G_OBJECT (check), "flags", GINT_TO_POINTER (options[i].flags));
|
||||
g_signal_connect (check, "toggled", G_CALLBACK (toggled_flag), area);
|
||||
gtk_box_pack_start (GTK_BOX (box), check, TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *vbox, *hbox, *area, *widget;
|
||||
guint i;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
//gdk_window_set_debug_updates (TRUE);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Pictures");
|
||||
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_container_add (GTK_CONTAINER (window), hbox);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
||||
|
||||
area = gtk_drawing_area_new ();
|
||||
gtk_widget_set_size_request (area, 400, 400);
|
||||
g_signal_connect (area, "draw", G_CALLBACK (draw_callback), NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), area, TRUE, TRUE, 0);
|
||||
|
||||
widget = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PAUSE);
|
||||
g_signal_connect (widget, "clicked", G_CALLBACK (rotation_toggled), area);
|
||||
rotation_toggled (GTK_BUTTON (widget), area);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0);
|
||||
|
||||
widget = create_optionsview (area);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (demos); i++)
|
||||
{
|
||||
GtkWidget *expander;
|
||||
|
||||
demos[i].create (&demos[i]);
|
||||
|
||||
demos[i].attached_picture = gtk_widget_style_picture (area, demos[i].picture);
|
||||
g_signal_connect (demos[i].attached_picture, "changed", G_CALLBACK (picture_changed), area);
|
||||
|
||||
expander = gtk_expander_new (demos[i].name);
|
||||
gtk_container_add (GTK_CONTAINER (expander), demos[i].widget);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, TRUE, 0);
|
||||
}
|
||||
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user