I’m trying to create a Volume (Cairo circle) button in gtk4. which can be rotate by mouse motion event. By clicking anywhere on the button and rotating it, the value 1-100 will be output. Tried a lot, maybe it’s beyond my knowledge.
Below is what i tried, with the mouse pointer on it, the circle is rotating. But the main problem is that the circle can’t be rotated properly by clicking anywhere on the circle; the volume indicator point(sub circle), moving directly to the mouse pointer and can’t figure out how to get the output in integer format. Can anyone check it?
#include <gtk/gtk.h>
#include <gtk/gtk.h>
#include <math.h>
float angel = 0.00;
//rotate the surface
cairo_surface_t *Rotate(cairo_surface_t *image, int degrees )
{
int w, h;
cairo_t *cr;
cairo_surface_t* tgt;
w = cairo_image_surface_get_width (image);
h = cairo_image_surface_get_height (image);
tgt = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
cr = cairo_create(tgt);
cairo_translate (cr, w/2, h/2);
cairo_rotate (cr, degrees* M_PI/180);
cairo_scale (cr, w/w, h/h);
cairo_translate (cr, -0.5*w, -0.5*h);
cairo_set_source_surface (cr, image, 0, 0);
cairo_paint (cr);
cairo_destroy(cr);
return tgt;
}
//draw circle
cairo_surface_t *draw_circle (int width, int height)
{
cairo_t *cr;
cairo_surface_t* tgt;
tgt = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create(tgt);
int radius;
if (width < height)
radius = width/2;
else
radius = height/2;
cairo_move_to (cr, width/2 + radius, height/2);
cairo_arc (cr, width/2, height/2, radius, 0.0, 2 * M_PI);
cairo_set_source_rgb (cr, 0.6, 0.8, 1.0);
cairo_fill_preserve (cr);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_stroke (cr);
cairo_arc (cr, width*93/100, height/2, radius*5/100, 0.0, 2 * M_PI);
cairo_set_source_rgb (cr, 0.9, 0.0, 1.0);
cairo_fill_preserve (cr);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_stroke (cr);
cairo_destroy(cr);
return tgt;
}
static void
draw_function (GtkDrawingArea *darea,
cairo_t *cr,
int width,
int height,
gpointer user_data)
{
cairo_surface_t *surF = draw_circle(width, height);
cairo_surface_t *rot = Rotate(surF, angel);
cairo_set_source_surface (cr, rot, 0, 0);
cairo_surface_destroy(rot);
cairo_paint (cr);
cairo_surface_destroy(surF);
//draw start and last indicator line
cairo_set_source_rgb(cr, 0, 1.0, 0);
cairo_set_line_width (cr, 3.5);
cairo_move_to (cr, 5, height-5);
cairo_line_to (cr, width*13/100, height*87/100);
cairo_move_to (cr, width-5, height-5);
cairo_line_to (cr, width*87/100, height*87/100);
cairo_stroke(cr);
}
void pointer_motion_event (GtkEventController *gesture,
gdouble x,
gdouble y,
gpointer user_data)
{
GdkModifierType state = gtk_event_controller_get_current_event_state(gesture);
if (state & GDK_BUTTON1_MASK) {
g_print ("mouse pointer %0.0f %0.0fn", x, y);
int width = gtk_widget_get_width(user_data);
int height = gtk_widget_get_height(user_data);
int cx = width/2, cy = height/2; //center of the object
int mx = x, my = y; // current mouse cursor position
float new_angle = atan2f(my - cy, mx - cx);
float deg = (new_angle * 180 / M_PI);
angel = deg;
printf ("%fn", deg);
}
gtk_widget_queue_draw(user_data);
}
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_window_present (GTK_WINDOW (window));
GtkWidget *darea = gtk_drawing_area_new();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (darea), 350);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (darea), 350);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (darea),
draw_function,
NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), darea);
GtkEventController *gesture_pos;
gesture_pos = gtk_event_controller_motion_new ();
gtk_widget_add_controller (darea, (GtkEventController *)gesture_pos);
gtk_event_controller_set_propagation_phase((GtkEventController *)gesture_pos, GTK_PHASE_CAPTURE);
g_signal_connect (gesture_pos, "motion", G_CALLBACK (pointer_motion_event), darea);
gtk_widget_show (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}