mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
38fa5ab57b
So we can use that one when translating event coordinates. Also adapt the widgetfocus demo to ensure this works. We should probably at some point delete either the int or the double version.
299 lines
8.3 KiB
C
299 lines
8.3 KiB
C
#include <gtk/gtk.h>
|
||
|
||
|
||
|
||
typedef struct _GtkFocusWidget GtkFocusWidget;
|
||
typedef struct _GtkFocusWidgetClass GtkFocusWidgetClass;
|
||
|
||
#define GTK_TYPE_FOCUS_WIDGET (gtk_focus_widget_get_type ())
|
||
#define GTK_FOCUS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GTK_TYPE_FOCUS_WIDGET, GtkFocusWidget))
|
||
#define GTK_FOCUS_WIDGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, GTK_TYPE_FOCUS_WIDGET, GtkFocusWidgetClass))
|
||
#define GTK_IS_FOCUS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, GTK_TYPE_FOCUS_WIDGET))
|
||
#define GTK_IS_FOCUS_WIDGET_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE(cls, GTK_TYPE_FOCUS_WIDGET))
|
||
#define GTK_FOCUS_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, GTK_TYPE_FOCUS_WIDGET, GtkFocusWidgetClass))
|
||
|
||
const char *css =
|
||
"* {"
|
||
" transition: none; "
|
||
"}"
|
||
"focuswidget {"
|
||
" padding: 30px;"
|
||
" font-size: 70%;"
|
||
"}"
|
||
"focuswidget button:nth-child(1) {"
|
||
" margin-right: 15px;"
|
||
" margin-bottom: 15px;"
|
||
"}"
|
||
"focuswidget button:nth-child(2) {"
|
||
" margin-left: 15px;"
|
||
" margin-bottom: 15px;"
|
||
"}"
|
||
"focuswidget button:nth-child(3) {"
|
||
" margin-right: 15px;"
|
||
" margin-top: 15px;"
|
||
"}"
|
||
"focuswidget button:nth-child(4) {"
|
||
" margin-left: 15px;"
|
||
" margin-top: 15px;"
|
||
"}"
|
||
"focuswidget button {"
|
||
" min-width: 80px;"
|
||
" min-height: 80px;"
|
||
" margin: 0px;"
|
||
" border: 5px solid green;"
|
||
" border-radius: 0px;"
|
||
" padding: 10px;"
|
||
" background-image: none;"
|
||
" background-color: white;"
|
||
" box-shadow: none;"
|
||
"}"
|
||
"focuswidget button:focus(visible) {"
|
||
" outline-width: 4px;"
|
||
" outline-color: yellow;"
|
||
"}"
|
||
"focuswidget button:hover {"
|
||
" background-color: black;"
|
||
" color: white;"
|
||
"}"
|
||
"focuswidget button label:hover {"
|
||
" background-color: green;"
|
||
"}"
|
||
;
|
||
|
||
struct _GtkFocusWidget
|
||
{
|
||
GtkWidget parent_instance;
|
||
double mouse_x;
|
||
double mouse_y;
|
||
|
||
union {
|
||
struct {
|
||
GtkWidget *child1;
|
||
GtkWidget *child2;
|
||
GtkWidget *child3;
|
||
GtkWidget *child4;
|
||
};
|
||
GtkWidget* children[4];
|
||
};
|
||
};
|
||
|
||
struct _GtkFocusWidgetClass
|
||
{
|
||
GtkWidgetClass parent_class;
|
||
};
|
||
|
||
GType gtk_focus_widget_get_type (void) G_GNUC_CONST;
|
||
|
||
|
||
G_DEFINE_TYPE(GtkFocusWidget, gtk_focus_widget, GTK_TYPE_WIDGET)
|
||
|
||
static void
|
||
gtk_focus_widget_size_allocate (GtkWidget *widget,
|
||
const GtkAllocation *allocation,
|
||
int baseline,
|
||
GtkAllocation *out_clip)
|
||
{
|
||
GtkFocusWidget *self = GTK_FOCUS_WIDGET (widget);
|
||
int child_width = (allocation->width) / 2;
|
||
int child_height = (allocation->height) / 2;
|
||
GtkAllocation child_alloc;
|
||
|
||
child_alloc.x = 0;
|
||
child_alloc.y = 0;
|
||
child_alloc.width = child_width;
|
||
child_alloc.height = child_height;
|
||
|
||
gtk_widget_size_allocate (self->child1, &child_alloc, -1, out_clip);
|
||
|
||
child_alloc.x += child_width;
|
||
|
||
gtk_widget_size_allocate (self->child2, &child_alloc, -1, out_clip);
|
||
|
||
child_alloc.y += child_height;
|
||
|
||
gtk_widget_size_allocate (self->child4, &child_alloc, -1, out_clip);
|
||
|
||
child_alloc.x -= child_width;
|
||
|
||
gtk_widget_size_allocate (self->child3, &child_alloc, -1, out_clip);
|
||
}
|
||
|
||
static void
|
||
gtk_focus_widget_measure (GtkWidget *widget,
|
||
GtkOrientation orientation,
|
||
int for_size,
|
||
int *minimum,
|
||
int *natural,
|
||
int *minimum_baseline,
|
||
int *natural_baseline)
|
||
{
|
||
GtkFocusWidget *self = GTK_FOCUS_WIDGET (widget);
|
||
int min, nat;
|
||
int i;
|
||
|
||
*minimum = 0;
|
||
*natural = 0;
|
||
|
||
for (i = 0; i < 4; i ++)
|
||
{
|
||
gtk_widget_measure (self->children[i], orientation, for_size,
|
||
&min, &nat, NULL, NULL);
|
||
|
||
*minimum = MAX (*minimum, min);
|
||
*natural = MAX (*natural, nat);
|
||
}
|
||
|
||
*minimum *= 2;
|
||
*natural *= 2;
|
||
}
|
||
|
||
static void
|
||
gtk_focus_widget_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
|
||
{
|
||
GtkFocusWidget *self = GTK_FOCUS_WIDGET (widget);
|
||
|
||
gtk_widget_snapshot_child (widget, self->child1, snapshot);
|
||
gtk_widget_snapshot_child (widget, self->child2, snapshot);
|
||
gtk_widget_snapshot_child (widget, self->child3, snapshot);
|
||
gtk_widget_snapshot_child (widget, self->child4, snapshot);
|
||
|
||
if (self->mouse_x != G_MININT && self->mouse_y != G_MININT)
|
||
{
|
||
PangoLayout *layout;
|
||
char *text;
|
||
GtkAllocation alloc;
|
||
graphene_rect_t bounds;
|
||
GdkRGBA black = {0, 0, 0, 1};
|
||
|
||
gtk_widget_get_allocation (widget, &alloc);
|
||
|
||
/* Since event coordinates and drawing is supposed to happen in the
|
||
* same coodinates space, this should all work out just fine. */
|
||
bounds.origin.x = self->mouse_x;
|
||
bounds.origin.y = -30;
|
||
bounds.size.width = 1;
|
||
bounds.size.height = alloc.height;
|
||
gtk_snapshot_append_color (snapshot,
|
||
&black,
|
||
&bounds,
|
||
"Crosshair 1");
|
||
|
||
bounds.origin.x = -30;
|
||
bounds.origin.y = self->mouse_y;
|
||
bounds.size.width = alloc.width;
|
||
bounds.size.height = 1;
|
||
gtk_snapshot_append_color (snapshot,
|
||
&black,
|
||
&bounds,
|
||
"Crosshair 2");
|
||
|
||
layout = gtk_widget_create_pango_layout (widget, NULL);
|
||
text = g_strdup_printf ("%.2f×%.2f", self->mouse_x, self->mouse_y);
|
||
pango_layout_set_text (layout, text, -1);
|
||
|
||
gtk_snapshot_render_layout (snapshot,
|
||
gtk_widget_get_style_context (widget),
|
||
self->mouse_x + 2,
|
||
self->mouse_y - 15, /* *shrug* */
|
||
layout);
|
||
|
||
g_free (text);
|
||
g_object_unref (layout);
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
gtk_focus_widget_event (GtkWidget *widget,
|
||
GdkEvent *event)
|
||
{
|
||
GtkFocusWidget *self = GTK_FOCUS_WIDGET (widget);
|
||
double x, y;
|
||
|
||
if (gdk_event_get_event_type (event) == GDK_MOTION_NOTIFY)
|
||
{
|
||
gdk_event_get_coords ((GdkEvent *)event, &x, &y);
|
||
|
||
self->mouse_x = x;
|
||
self->mouse_y = y;
|
||
|
||
gtk_widget_queue_draw (widget);
|
||
}
|
||
|
||
return GDK_EVENT_PROPAGATE;
|
||
}
|
||
|
||
static void
|
||
gtk_focus_widget_finalize (GObject *object)
|
||
{
|
||
GtkFocusWidget *self = GTK_FOCUS_WIDGET (object);
|
||
|
||
gtk_widget_unparent (self->child1);
|
||
gtk_widget_unparent (self->child2);
|
||
gtk_widget_unparent (self->child3);
|
||
gtk_widget_unparent (self->child4);
|
||
|
||
G_OBJECT_CLASS (gtk_focus_widget_parent_class)->finalize (object);
|
||
}
|
||
|
||
static void
|
||
gtk_focus_widget_init (GtkFocusWidget *self)
|
||
{
|
||
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
|
||
|
||
self->child1 = gtk_button_new_with_label ("1");
|
||
gtk_widget_set_parent (self->child1, GTK_WIDGET (self));
|
||
self->child2 = gtk_button_new_with_label ("2");
|
||
gtk_widget_set_parent (self->child2, GTK_WIDGET (self));
|
||
self->child3 = gtk_button_new_with_label ("3");
|
||
gtk_widget_set_parent (self->child3, GTK_WIDGET (self));
|
||
self->child4 = gtk_button_new_with_label ("4");
|
||
gtk_widget_set_parent (self->child4, GTK_WIDGET (self));
|
||
|
||
self->mouse_x = G_MININT;
|
||
self->mouse_y = G_MININT;
|
||
}
|
||
|
||
static void
|
||
gtk_focus_widget_class_init (GtkFocusWidgetClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||
|
||
object_class->finalize = gtk_focus_widget_finalize;
|
||
|
||
widget_class->snapshot = gtk_focus_widget_snapshot;
|
||
widget_class->measure = gtk_focus_widget_measure;
|
||
widget_class->size_allocate = gtk_focus_widget_size_allocate;
|
||
widget_class->event = gtk_focus_widget_event;
|
||
|
||
gtk_widget_class_set_css_name (widget_class, "focuswidget");
|
||
}
|
||
|
||
int
|
||
main()
|
||
{
|
||
GtkWidget *window;
|
||
GtkWidget *widget;
|
||
GtkCssProvider *provider;
|
||
|
||
gtk_init ();
|
||
|
||
provider = gtk_css_provider_new ();
|
||
gtk_css_provider_load_from_data (provider, css, -1);
|
||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||
GTK_STYLE_PROVIDER (provider),
|
||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||
|
||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||
widget = g_object_new (GTK_TYPE_FOCUS_WIDGET, NULL);
|
||
|
||
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
|
||
|
||
gtk_container_add (GTK_CONTAINER (window), widget);
|
||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
||
|
||
gtk_widget_show (window);
|
||
|
||
gtk_main ();
|
||
}
|