Use a context menu

Move the toggling of smoothness to a context menu
on each point. This menu will carry more items in
the future.
This commit is contained in:
Matthias Clasen
2020-11-20 13:30:08 -05:00
parent 4c23a9fa6e
commit 8993756a84

View File

@@ -3,29 +3,33 @@
#define RADIUS 5
G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget)
typedef struct
{
gboolean edit;
gboolean smooth;
} PointData;
typedef struct
struct _DemoWidget
{
GtkWidget parent_instance;
graphene_point_t *points;
int n_points;
PointData *point_data; /* length is n_points / 3 */
int dragged;
int context;
gboolean symmetric;
gboolean edit;
} DemoWidget;
typedef struct
GtkWidget *menu;
GActionMap *actions;
};
struct _DemoWidgetClass
{
GtkWidgetClass parent_class;
} DemoWidgetClass;
GType demo_widget_get_type (void) G_GNUC_CONST;
};
G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET)
@@ -149,6 +153,72 @@ drag_end (GtkGestureDrag *gesture,
self->symmetric = FALSE;
}
static void
toggle_smooth (GSimpleAction *action,
GVariant *value,
gpointer data)
{
DemoWidget *self = DEMO_WIDGET (data);
gboolean smooth = g_variant_get_boolean (value);
self->point_data[self->context / 3].smooth = smooth;
if (smooth)
{
graphene_point_t *p, *c, *c2;
float a, d;
p = &self->points[self->context];
c = &self->points[(self->context - 1 + self->n_points) % self->n_points];
c2 = &self->points[(self->context + 1 + self->n_points) % self->n_points];
a = atan2 (c2->y - p->y, c2->x - p->x) + M_PI;
d = dist (c, p);
c->x = p->x + d * cos (a);
c->y = p->y + d * sin (a);
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pressed (GtkGestureClick *gesture,
int n_press,
double x,
double y,
DemoWidget *self)
{
graphene_point_t m = GRAPHENE_POINT_INIT (x, y);
int i;
int button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (!self->edit)
return;
if (button != GDK_BUTTON_SECONDARY)
return;
for (i = 0; i < self->n_points; i++)
{
if (i % 3 != 0)
continue;
if (dist (&self->points[i], &m) < RADIUS)
{
GAction *action;
self->context = i;
action = g_action_map_lookup_action (self->actions, "smooth");
g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (self->point_data[i / 3].smooth));
gtk_popover_set_pointing_to (GTK_POPOVER (self->menu),
&(const GdkRectangle){ x, y, 1, 1 });
gtk_popover_popup (GTK_POPOVER (self->menu));
return;
}
}
}
static void
released (GtkGestureClick *gesture,
int n_press,
@@ -175,6 +245,7 @@ released (GtkGestureClick *gesture,
}
else if (button == GDK_BUTTON_SECONDARY)
{
self->context = i;
self->point_data[i / 3].smooth = !self->point_data[i / 3].smooth;
if (self->point_data[i / 3].smooth)
{
@@ -191,8 +262,6 @@ released (GtkGestureClick *gesture,
c->y = p->y + d * sin (a);
}
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
}
@@ -246,6 +315,9 @@ static void
demo_widget_init (DemoWidget *self)
{
GtkGesture *gesture;
GMenu *menu;
GMenuItem *item;
GSimpleAction *action;
self->dragged = -1;
self->edit = FALSE;
@@ -259,10 +331,27 @@ demo_widget_init (DemoWidget *self)
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed), self);
g_signal_connect (gesture, "released", G_CALLBACK (released), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
init_points (self);
self->actions = G_ACTION_MAP (g_simple_action_group_new ());
action = g_simple_action_new_stateful ("smooth", NULL, g_variant_new_boolean (FALSE));
g_signal_connect (action, "change-state", G_CALLBACK (toggle_smooth), self);
g_action_map_add_action (G_ACTION_MAP (self->actions), G_ACTION (action));
gtk_widget_insert_action_group (GTK_WIDGET (self), "point", G_ACTION_GROUP (self->actions));
menu = g_menu_new ();
item = g_menu_item_new ("Smooth", "point.smooth");
g_menu_append_item (menu, item);
g_object_unref (item);
self->menu = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
g_object_unref (menu);
gtk_widget_set_parent (self->menu, GTK_WIDGET (self));
}
static void
@@ -410,13 +499,40 @@ demo_widget_measure (GtkWidget *widget,
*natural_size = 200;
}
static void
demo_widget_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
DemoWidget *self = DEMO_WIDGET (widget);
gtk_native_check_resize (GTK_NATIVE (self->menu));
}
static void
demo_widget_dispose (GObject *object)
{
DemoWidget *self = DEMO_WIDGET (object);
g_clear_pointer (&self->points, g_free);
g_clear_pointer (&self->point_data, g_free);
g_clear_pointer (&self->menu, gtk_widget_unparent);
G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object);
}
static void
demo_widget_class_init (DemoWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo_widget_dispose;
widget_class->snapshot = demo_widget_snapshot;
widget_class->measure = demo_widget_measure;
widget_class->size_allocate = demo_widget_size_allocate;
}
static GtkWidget *