Created
October 27, 2022 23:20
-
-
Save Fenshu28/cb91acffd95d5a9cee6da2e5e61da5ae to your computer and use it in GitHub Desktop.
Drggable widget in GTK 3 with C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <gtk/gtk.h> | |
// Source: | |
// http://www.linuxforums.org/forum/programming-scripting/117713-gtk-moving-widget-mouse-post906490.html#post906490 | |
// higher values make movement more performant | |
// lower values make movement smoother | |
const gint Sensitivity = 1; | |
const gint EvMask = GDK_BUTTON_PRESS_MASK | GDK_BUTTON1_MOTION_MASK; | |
GtkWidget *fixed; | |
int offsetx, offsety, px, py, maxx, maxy; | |
inline static int Min(const int a, const int b) { return b < a ? b : a; } | |
inline static int Max(const int a, const int b) { return b > a ? b : a; } | |
inline static int RoundDownToMultiple(const int i, const int m) | |
{ | |
return i/m*m; | |
} | |
inline static int RoundToNearestMultiple(const int i, const int m) | |
{ | |
if (i % m > (double)m / 2.0d) | |
return (i/m+1)*m; | |
return i/m*m; | |
} | |
static void destroy( GtkWidget *widget, gpointer data ) { gtk_main_quit (); } | |
static gboolean button_press_event( GtkWidget *w, GdkEventButton *event ) | |
{ | |
if (event->button == 1) { | |
GtkWidget* p = gtk_widget_get_parent(w); | |
// offset == distance of parent widget from edge of screen ... | |
gdk_window_get_position(gtk_widget_get_window(p), &offsetx, &offsety); | |
// plus distance from pointer to edge of widget | |
offsetx += (int)event->x; | |
offsety += (int)event->y; | |
// maxx, maxy both relative to the parent | |
// note that we're rounding down now so that these max values don't get | |
// rounded upward later and push the widget off the edge of its parent. | |
maxx = RoundDownToMultiple(gtk_widget_get_allocated_width(p) - gtk_widget_get_allocated_width(w), Sensitivity); | |
maxy = RoundDownToMultiple(gtk_widget_get_allocated_height(p) - gtk_widget_get_allocated_height(w), Sensitivity); | |
} | |
return TRUE; | |
} | |
static gboolean motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) | |
{ | |
// x_root,x_root relative to screen | |
// x,y relative to parent (fixed widget) | |
// px,py stores previous values of x,y | |
// get starting values for x,y | |
int x = (int)event->x_root - offsetx; | |
int y = (int)event->y_root - offsety; | |
// make sure the potential coordinates x,y: | |
// 1) will not push any part of the widget outside of its parent container | |
// 2) is a multiple of Sensitivity | |
x = RoundToNearestMultiple(Max(Min(x, maxx), 0), Sensitivity); | |
y = RoundToNearestMultiple(Max(Min(y, maxy), 0), Sensitivity); | |
if (x != px || y != py) { | |
px = x; | |
py = y; | |
gtk_fixed_move(GTK_FIXED(fixed), widget, x, y); | |
} | |
return TRUE; | |
} | |
GtkWidget* make_button(const gchar* const text) | |
{ | |
GtkWidget* b = gtk_button_new_with_label(text); | |
gtk_widget_add_events(b, EvMask); | |
g_signal_connect(b, "button_press_event", G_CALLBACK(button_press_event), NULL); | |
g_signal_connect(b, "motion_notify_event",G_CALLBACK(motion_notify_event), NULL); | |
gtk_widget_show(b); | |
return b; | |
} | |
int main(int argc, char *argv[] ) | |
{ | |
gtk_init (&argc, &argv); | |
// top level window | |
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); | |
gtk_container_set_border_width (GTK_CONTAINER (window), 0); | |
g_signal_connect (G_OBJECT (window), "destroy",G_CALLBACK (destroy), NULL); | |
// fixed container | |
fixed=gtk_fixed_new(); | |
gtk_container_add((GtkContainer*)window,(GtkWidget*)fixed); | |
gtk_widget_show (fixed); | |
// buttons | |
gtk_fixed_put(GTK_FIXED(fixed), make_button("A button"), 50, 50); | |
gtk_fixed_put(GTK_FIXED(fixed), make_button("Another button"), 250, 100); | |
gtk_widget_show (window); | |
gtk_main (); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment