Clean up the About animation
This commit is contained in:
parent
4f19a67da3
commit
3bf41993a3
80
fiv.c
80
fiv.c
|
@ -208,6 +208,11 @@ make_key_window(void)
|
||||||
|
|
||||||
// --- About -------------------------------------------------------------------
|
// --- About -------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gint cx, cy;
|
||||||
|
cairo_pattern_t *v_pattern;
|
||||||
|
} AboutContext;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_about_map(GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
|
on_about_map(GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -224,30 +229,30 @@ on_about_unmap(GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
|
||||||
gdk_frame_clock_end_updating(clock);
|
gdk_frame_clock_end_updating(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint g_about_x, g_about_y;
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
on_about_motion(G_GNUC_UNUSED GtkWidget *widget, GdkEventMotion *event,
|
on_about_motion(
|
||||||
G_GNUC_UNUSED gpointer user_data)
|
G_GNUC_UNUSED GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
|
||||||
{
|
{
|
||||||
g_about_x = event->x;
|
AboutContext *ctx = user_data;
|
||||||
g_about_y = event->y;
|
ctx->cx = event->x;
|
||||||
|
ctx->cy = event->y;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
on_about_leave(G_GNUC_UNUSED GtkWidget *widget,
|
on_about_leave(G_GNUC_UNUSED GtkWidget *widget,
|
||||||
G_GNUC_UNUSED GdkEventCrossing *event, G_GNUC_UNUSED gpointer user_data)
|
G_GNUC_UNUSED GdkEventCrossing *event, gpointer user_data)
|
||||||
{
|
{
|
||||||
g_about_x = 0;
|
AboutContext *ctx = user_data;
|
||||||
g_about_y = 0;
|
ctx->cx = -1;
|
||||||
|
ctx->cy = -1;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { ABOUT_SIZE = 48, ABOUT_SCALE = 3, ABOUT_HEIGHT = ABOUT_SIZE * 4 / 3 };
|
enum { ABOUT_SIZE = 48, ABOUT_SCALE = 3, ABOUT_HEIGHT = ABOUT_SIZE * 4 / 3 };
|
||||||
|
|
||||||
// The mismatching resolution is incidental, and kept for interesting looks.
|
// The mismatching resolution is incidental, and kept for interesting looks.
|
||||||
cairo_pattern_t *
|
static cairo_pattern_t *
|
||||||
make_infinite_v_pattern(void)
|
make_infinite_v_pattern(void)
|
||||||
{
|
{
|
||||||
cairo_surface_t *surface =
|
cairo_surface_t *surface =
|
||||||
|
@ -260,9 +265,10 @@ make_infinite_v_pattern(void)
|
||||||
cairo_close_path(cr);
|
cairo_close_path(cr);
|
||||||
|
|
||||||
cairo_pattern_t *gradient = cairo_pattern_create_linear(0, 7, 0, 46);
|
cairo_pattern_t *gradient = cairo_pattern_create_linear(0, 7, 0, 46);
|
||||||
cairo_pattern_add_color_stop_rgba(gradient, 1, 1, 0x66 / 255., 0, 1);
|
cairo_pattern_add_color_stop_rgb(gradient, 1, 1, 0x66 / 255., 0);
|
||||||
cairo_pattern_add_color_stop_rgba(gradient, 0, 1, 0xaa / 255., 0, 1);
|
cairo_pattern_add_color_stop_rgb(gradient, 0, 1, 0xaa / 255., 0);
|
||||||
cairo_set_source(cr, gradient);
|
cairo_set_source(cr, gradient);
|
||||||
|
cairo_pattern_destroy(gradient);
|
||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
|
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
|
@ -329,8 +335,9 @@ draw_ligature(cairo_t *cr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
on_about_draw(GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer user_data)
|
on_about_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
AboutContext *ctx = user_data;
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation(widget, &allocation);
|
gtk_widget_get_allocation(widget, &allocation);
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
||||||
|
@ -342,9 +349,9 @@ on_about_draw(GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer user_data)
|
||||||
|
|
||||||
cairo_save(cr);
|
cairo_save(cr);
|
||||||
cairo_translate(cr, ABOUT_SIZE / 2, ABOUT_SIZE / 2);
|
cairo_translate(cr, ABOUT_SIZE / 2, ABOUT_SIZE / 2);
|
||||||
if (g_about_x && g_about_y) {
|
if (ctx->cx >= 0 && ctx->cy >= 0) {
|
||||||
gint dx = g_about_x - allocation.width / 2;
|
gint dx = ctx->cx - allocation.width / 2;
|
||||||
gint dy = g_about_y - ABOUT_SIZE * ABOUT_SCALE * 3 / 4;
|
gint dy = ctx->cy - ABOUT_SIZE * ABOUT_SCALE * 3 / 4;
|
||||||
cairo_rotate(cr, atan2(dy, dx) - M_PI_2);
|
cairo_rotate(cr, atan2(dy, dx) - M_PI_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,25 +359,20 @@ on_about_draw(GtkWidget *widget, cairo_t *cr, G_GNUC_UNUSED gpointer user_data)
|
||||||
gint64 t = gdk_frame_clock_get_frame_time(clock);
|
gint64 t = gdk_frame_clock_get_frame_time(clock);
|
||||||
cairo_translate(cr, 0, (gint64) (t / 4e4) % ABOUT_SIZE);
|
cairo_translate(cr, 0, (gint64) (t / 4e4) % ABOUT_SIZE);
|
||||||
|
|
||||||
cairo_pattern_t *v = make_infinite_v_pattern();
|
cairo_set_source(cr, ctx->v_pattern);
|
||||||
cairo_set_source(cr, v);
|
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
|
|
||||||
cairo_save(cr);
|
|
||||||
cairo_translate(cr, ABOUT_SIZE / 2, 14 /* Through trial and error. */);
|
cairo_translate(cr, ABOUT_SIZE / 2, 14 /* Through trial and error. */);
|
||||||
cairo_scale(cr, 1, -1);
|
cairo_scale(cr, 1, -1);
|
||||||
cairo_set_source(cr, v);
|
cairo_set_source(cr, ctx->v_pattern);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
cairo_restore(cr);
|
|
||||||
|
|
||||||
cairo_pattern_destroy(v);
|
|
||||||
cairo_restore(cr);
|
cairo_restore(cr);
|
||||||
draw_ligature(cr);
|
draw_ligature(cr);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkWidget *
|
static void
|
||||||
make_about_dialog(GtkWidget *parent)
|
show_about_dialog(GtkWidget *parent)
|
||||||
{
|
{
|
||||||
GtkWidget *dialog = gtk_widget_new(GTK_TYPE_DIALOG, "use-header-bar", TRUE,
|
GtkWidget *dialog = gtk_widget_new(GTK_TYPE_DIALOG, "use-header-bar", TRUE,
|
||||||
"title", "About", "transient-for", parent, "destroy-with-parent", TRUE,
|
"title", "About", "transient-for", parent, "destroy-with-parent", TRUE,
|
||||||
|
@ -381,16 +383,18 @@ make_about_dialog(GtkWidget *parent)
|
||||||
gtk_widget_set_size_request(
|
gtk_widget_set_size_request(
|
||||||
area, ABOUT_SIZE * ABOUT_SCALE * 2, ABOUT_HEIGHT * ABOUT_SCALE);
|
area, ABOUT_SIZE * ABOUT_SCALE * 2, ABOUT_HEIGHT * ABOUT_SCALE);
|
||||||
|
|
||||||
|
AboutContext ctx = {
|
||||||
|
.cx = -1, .cy = -1, .v_pattern = make_infinite_v_pattern()};
|
||||||
gtk_widget_add_events(
|
gtk_widget_add_events(
|
||||||
area, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
|
area, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
area, "motion-notify-event", G_CALLBACK(on_about_motion), NULL);
|
area, "motion-notify-event", G_CALLBACK(on_about_motion), &ctx);
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
area, "leave-notify-event", G_CALLBACK(on_about_leave), NULL);
|
area, "leave-notify-event", G_CALLBACK(on_about_leave), &ctx);
|
||||||
|
|
||||||
g_signal_connect(area, "draw", G_CALLBACK(on_about_draw), NULL);
|
g_signal_connect(area, "draw", G_CALLBACK(on_about_draw), &ctx);
|
||||||
g_signal_connect(area, "map", G_CALLBACK(on_about_map), NULL);
|
g_signal_connect(area, "map", G_CALLBACK(on_about_map), &ctx);
|
||||||
g_signal_connect(area, "unmap", G_CALLBACK(on_about_unmap), NULL);
|
g_signal_connect(area, "unmap", G_CALLBACK(on_about_unmap), &ctx);
|
||||||
|
|
||||||
// The rest is approximately copying GTK+'s own gtkaboutdialog.ui.
|
// The rest is approximately copying GTK+'s own gtkaboutdialog.ui.
|
||||||
GtkWidget *name = gtk_label_new(NULL);
|
GtkWidget *name = gtk_label_new(NULL);
|
||||||
|
@ -419,7 +423,7 @@ make_about_dialog(GtkWidget *parent)
|
||||||
|
|
||||||
GBytes *license =
|
GBytes *license =
|
||||||
g_resources_lookup_data("/LICENSE", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
|
g_resources_lookup_data("/LICENSE", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
|
||||||
g_return_val_if_fail(license != NULL, dialog);
|
g_return_if_fail(license != NULL);
|
||||||
gchar *escaped = g_markup_escape_text(g_bytes_get_data(license, NULL), -1);
|
gchar *escaped = g_markup_escape_text(g_bytes_get_data(license, NULL), -1);
|
||||||
g_bytes_unref(license);
|
g_bytes_unref(license);
|
||||||
|
|
||||||
|
@ -449,7 +453,11 @@ make_about_dialog(GtkWidget *parent)
|
||||||
GDK_HINT_MAX_SIZE);
|
GDK_HINT_MAX_SIZE);
|
||||||
|
|
||||||
gtk_widget_grab_focus(viewer);
|
gtk_widget_grab_focus(viewer);
|
||||||
return dialog;
|
gtk_widget_show_all(dialog);
|
||||||
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
|
||||||
|
cairo_pattern_destroy(ctx.v_pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main --------------------------------------------------------------------
|
// --- Main --------------------------------------------------------------------
|
||||||
|
@ -1068,14 +1076,10 @@ on_key_press(G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event,
|
||||||
break;
|
break;
|
||||||
case GDK_SHIFT_MASK:
|
case GDK_SHIFT_MASK:
|
||||||
switch (event->keyval) {
|
switch (event->keyval) {
|
||||||
case GDK_KEY_F1: {
|
case GDK_KEY_F1:
|
||||||
GtkWidget *dialog = make_about_dialog(g.window);
|
show_about_dialog(g.window);
|
||||||
gtk_widget_show_all(dialog);
|
|
||||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
switch (event->keyval) {
|
switch (event->keyval) {
|
||||||
|
|
Loading…
Reference in New Issue