Find the answer to your Linux question:
Results 1 to 3 of 3
I'm making a widget layout editor as part of a project I'm working on. I managed to use a GtkEventBox per widget (on a gtkFixed container) to intercept mouse drag ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Mar 2008
    Posts
    34

    gtk: moving a widget with the mouse?


    I'm making a widget layout editor as part of a project I'm working on.

    I managed to use a GtkEventBox per widget (on a gtkFixed container) to intercept mouse drag events.

    The mouse coordinates looked fine and dandy, until I started moving the widget then I started getting a bunch of spurious wildly off mouse event coordinates as the widget moved of the gtkFixed container
    (I tried a number of things to attempt to filter these events with no joy)

    I tried putting a single gtkEventBox over the widgets to be moved, but this seemed to visually obscure the widgets??

    I tried a bunch of different things, and I'm at the point of starting again, has anyone else moved gtkWidgets about with the mouse?

    I'll probably look at the glade source, but is quite a large code base and its gonna be hard to track down what I need.

    Any ideas?

    Thanks
    C

  2. #2
    Just Joined!
    Join Date
    Mar 2008
    Posts
    34
    turns out you dont even need to use GtkEventBox's....

    Code:
    #include <gtk/gtk.h>
    
    
    static gboolean delete_event( GtkWidget *widget, GdkEvent  *event, gpointer   data ) {
        g_print ("delete event occurred\n");
    
        /* Change TRUE to FALSE and the main window will be destroyed with
         * a "delete_event". */
    
        return false;
    }
    
    /* Another callback */
    static void destroy( GtkWidget *widget, gpointer   data ) {
        gtk_main_quit ();
    }
    
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *button2;
    GtkWidget *fixed;
    
    int sx,sy;
    
    static gboolean button_press_event( GtkWidget *widget, GdkEventButton *event ) {
    	if (event->button == 1 ) printf("but down  %i , %i\n", (int)event->x, (int)event->y);
    	sx=(int)event->x;
    	sy=(int)event->y;
    
    	return TRUE;
    }
    
    static gboolean
    motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) {
    
    	int x, y;
    	GdkModifierType state;
    	gdk_window_get_pointer (window->window, &x, &y, &state);
    	
    	if (state & GDK_BUTTON1_MASK) {
    		printf(" %i , %i \n", x-sx, y-sy);
    		gtk_fixed_move( (GtkFixed*)fixed,(GtkWidget*)widget, x-sx, y-sy );
    	
    	}
    
    	return TRUE;
    }
    
    
    int main( int   argc, char *argv[] )
    {
    
    
        
        gtk_init (&argc, &argv);
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    	button = gtk_button_new_with_label ("A button");
    	button2 = gtk_button_new_with_label ("Another button");
    
    	fixed=gtk_fixed_new();
    
    
    	gtk_container_add((GtkContainer*)window,(GtkWidget*)fixed);
    
    	gtk_fixed_put( (GtkFixed*)fixed,button,50,50 );
    	gtk_fixed_put( (GtkFixed*)fixed,button2,250,100 );
    
    
        g_signal_connect (G_OBJECT (window), "delete_event",G_CALLBACK (delete_event), NULL);
        g_signal_connect (G_OBJECT (window), "destroy",G_CALLBACK (destroy), NULL);
    
    	gtk_signal_connect (GTK_OBJECT (button), "button_press_event",(GtkSignalFunc) button_press_event, NULL);
    	gtk_signal_connect (GTK_OBJECT (button), "motion_notify_event",(GtkSignalFunc) motion_notify_event, NULL);
    
    	gtk_signal_connect (GTK_OBJECT (button2), "button_press_event",(GtkSignalFunc) button_press_event, NULL);
    	gtk_signal_connect (GTK_OBJECT (button2), "motion_notify_event",(GtkSignalFunc) motion_notify_event, NULL);
    
        gtk_container_set_border_width (GTK_CONTAINER (window), 0);
    
    	gtk_widget_set_events(window, GDK_EXPOSURE_MASK
    			 | GDK_LEAVE_NOTIFY_MASK
    			 | GDK_BUTTON_PRESS_MASK
    			 | GDK_POINTER_MOTION_MASK
    			 | GDK_POINTER_MOTION_HINT_MASK); 
    
    	gtk_widget_set_events(button, GDK_EXPOSURE_MASK
    			 | GDK_LEAVE_NOTIFY_MASK
    			 | GDK_BUTTON_PRESS_MASK
    			 | GDK_POINTER_MOTION_MASK
    			 | GDK_POINTER_MOTION_HINT_MASK); 
    
    	gtk_widget_set_events(button2, GDK_EXPOSURE_MASK
    			 | GDK_LEAVE_NOTIFY_MASK
    			 | GDK_BUTTON_PRESS_MASK
    			 | GDK_POINTER_MOTION_MASK
    			 | GDK_POINTER_MOTION_HINT_MASK); 
    
    
        gtk_widget_show (button);
        gtk_widget_show (button2);
        gtk_widget_show (fixed);
        gtk_widget_show (window);
    
        
        gtk_main ();
        
        return 0;
    }

  3. #3
    Just Joined!
    Join Date
    Oct 2012
    Posts
    1

    Cool Follow-up

    Quote Originally Posted by Chris_C View Post
    turns out you dont even need to use GtkEventBox's....
    Hi Chris -

    Thanks very much for posting your code. It helped me a lot getting my project off the ground. I thought I might share my rendition as well for anyone that might be able to benefit from it. This is based on your code (as I'm sure you'll recognize), but it also adds a bit of logic to do the following:

    1) prevent the moving widget from leaving its container
    2) allow the client to select the level of movement sensitivity thereby allowing a performance vs. smoothness tweak

    I'm sure this could be done better, and I would love for someone to reply with more improvements. Cheers!

    Ian

    Code:
    #include <gtk/gtk.h>
    
    // higher values make movement more performant
    // lower values make movement smoother
    const gint Sensitivity = 10;
    
    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 = w->parent;
    		// offset == distance of parent widget from edge of screen ...
    		gdk_window_get_position(p->window, &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(p->allocation.width - w->allocation.width, Sensitivity);
    		maxy = RoundDownToMultiple(p->allocation.height - w->allocation.height, 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);
    	gtk_signal_connect(GTK_OBJECT(b), "button_press_event", (GtkSignalFunc)button_press_event, NULL);
    	gtk_signal_connect(GTK_OBJECT(b), "motion_notify_event", (GtkSignalFunc)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;
    }

  4. $spacer_open
    $spacer_close

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •