A smooth effect with GTK+

Mike Massonnet | Posted 3 months, 6 days ago on February 18, 2006

Did you try the Beta of GAIM2 ? In the discussion window there is a nice smooth effect, when the discussion scrolls down after you get or send a message. Also in GParted there is this effect when you show or hide a panel.

Now, if you are looking on how this effect is done, read the source :)

#include <stdlib.h>
#include <gtk/gtk.h>

#define DEBUG 1

void openclose_panel(GtkWidget*, gpointer);
void open_panel();
void close_panel();

GtkWidget *pWindow;
GtkWidget *pPanel;
GtkWidget *pButton;
GtkWidget *pLabel;

int 
main(int argc, char **argv)
  {
    /* Initialization of GTK+ */
    gtk_init(&argc, &argv);
    
    /* The window */
    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow), "¡Panned!");
    gtk_window_set_default_size(GTK_WINDOW(pWindow), 450, 300);
    
    /* Panel */
    pPanel = gtk_vpaned_new();
    gtk_container_add(GTK_CONTAINER(pWindow), pPanel);
    /* Button */
    pButton=gtk_button_new_with_label("Close the panel");
    gtk_paned_pack1(GTK_PANED(pPanel), pButton, FALSE, FALSE);
    /* Label */
    pLabel = gtk_label_new( "Hello" );
    gtk_paned_pack2(GTK_PANED(pPanel), pLabel, TRUE, FALSE);
    
    /* Show */
    gtk_widget_show_all(pWindow);
    /* Callbacks */
    g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(pButton), "clicked", G_CALLBACK(openclose_panel), NULL);
    /* Cycle loop and so on */
    gtk_main();
    
    return EXIT_SUCCESS;
  }

void 
openclose_panel(GtkWidget *pWidget, gpointer pData)
  {
  	gboolean is_hiden = !(GTK_WIDGET_FLAGS (pLabel) & GTK_VISIBLE);
  	if (DEBUG) printf("is_hiden:%d\n", is_hiden);
  	
  	if (is_hiden)
  	  {
  	    gtk_widget_show(pLabel);
  	    gtk_label_set_text(GTK_LABEL(pLabel), "Hello");
  	    open_panel();
  	    gtk_button_set_label(GTK_BUTTON(pButton), "Close the panel");
  	  }
  	else
  	  {
  	    gtk_label_set_text(GTK_LABEL(pLabel), "Bye");
  	    close_panel();
  	    gtk_widget_hide(pLabel);
  	    gtk_button_set_label(GTK_BUTTON(pButton), "Open the panel");
  	  }
  }

void
open_panel()
  {
    gint pos = gtk_paned_get_position(GTK_PANED(pPanel));
    if (DEBUG)
      {
        gint width,height;
        gtk_window_get_size(GTK_WINDOW(pWindow), &width, &height);
        printf("div_pos:%d/%d\n", gtk_paned_get_position(GTK_PANED(pPanel)) , \
        height);
      }
    
    /*  *  *  *  *  *  *  */
    /* Start the resizing */
    /*  *  *  *  *  *  *  */
    while (pos > 0)
      {
        pos -= 5;
        gtk_paned_set_position(GTK_PANED(pPanel), pos);
        while (gtk_events_pending())
          {
            gtk_main_iteration();
          }
      }
  }

void
close_panel()
  {
    gint pos = gtk_paned_get_position(GTK_PANED(pPanel));
    gint width,height;
    gtk_window_get_size(GTK_WINDOW(pWindow), &width, &height);
    if (DEBUG) printf("div_pos:%d/%d\n", gtk_paned_get_position(GTK_PANED(pPanel)) , \
        height);
    
    /*  *  *  *  *  *  *  */
    /* Start the resizing */
    /*  *  *  *  *  *  *  */
    while (pos < height)
      {
        pos += 5;
        gtk_paned_set_position(GTK_PANED(pPanel), pos);
        while (gtk_events_pending())
          {
            gtk_main_iteration();
          }
      }
  }

The important part is the resizing where you reduce or expand the size of a widget in a loop, and each time you set the new size in the loop, you need to get into another loop to be able to see the effect:

while (gtk_events_pending())
  {
    gtk_main_iteration();
  }

It is really easy and gives the application a nice impression :)

Earlier posts