aboutsummaryrefslogblamecommitdiffstats
path: root/widgets/shortcut-bar/e-shortcut-bar.c
blob: 842a8927f961a8f3173c26d4810fde2cd2382fdc (plain) (tree)

















































                                                                               
                         










                                                                                                                        
                                                    

































                                                                                  
                                                                                
                                                                          
                                                              





















































































































































































                                                                                                                                                                      
                         








                                                                           

















































































































































                                                                                              
                         















































































                                                                                                                                    
                  



























                                                                                                                                                     
                  


                                           
                                


                                                
                                                            




                                                                 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/* 
 * Author : 
 *  Damon Chaplin <damon@gtk.org>
 *
 * Copyright 1999, Helix Code, Inc.
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

/*
 * ShortcutBar displays a vertical bar with a number of Groups, each of which
 * contains any number of icons. It is used on the left of the main application
 * window so users can easily access items such as folders and files.
 */

#include <string.h>
#include <gnome.h>

#include "e-shortcut-bar.h"
#include "e-clipped-label.h"
#include "e-vscrolled-bar.h"

/* Drag and Drop stuff. */
enum {
    TARGET_SHORTCUT
};
static GtkTargetEntry target_table[] = {
    { "E-SHORTCUT",     0, TARGET_SHORTCUT }
};
static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);

typedef struct _EShortcutBarBuiltinType  EShortcutBarBuiltinType;
struct _EShortcutBarBuiltinType {
    gchar *name;
    gchar *filename;
    GdkPixbuf *image;
};

EShortcutBarBuiltinType e_shortcut_bar_builtin_types[] = {
    { "folder:",    "gnome-word.png",   NULL },
    { "calendar:",  "gnome-calendar.png",   NULL },
    { "todo:",  "gnome-cromagnon.png",  NULL },
    { "contacts:",  "gnome-ccthemes.png",   NULL }
};
static gint e_shortcut_bar_num_builtin_types = sizeof (e_shortcut_bar_builtin_types) / sizeof (EShortcutBarBuiltinType);

gboolean e_shortcut_bar_default_type_image_loaded = FALSE;
GdkPixbuf *e_shortcut_bar_default_type_image = NULL;
gchar *e_shortcut_bar_default_type_filename = "gnome-balsa2.png";

static void e_shortcut_bar_class_init (EShortcutBarClass *class);
static void e_shortcut_bar_init (EShortcutBar *shortcut_bar);
static void e_shortcut_bar_destroy (GtkObject *object);
static void e_shortcut_bar_set_canvas_style (EShortcutBar *shortcut_bar,
                         GtkWidget *canvas);
static void e_shortcut_bar_item_selected (EIconBar *icon_bar,
                      GdkEvent *event,
                      gint item_num,
                      EShortcutBar *shortcut_bar);
static void e_shortcut_bar_item_dragged (EIconBar *icon_bar,
                     GdkEvent *event,
                     gint item_num,
                     EShortcutBar *shortcut_bar);
static void e_shortcut_bar_on_drag_data_get (GtkWidget          *widget,
                         GdkDragContext     *context,
                         GtkSelectionData   *selection_data,
                         guint               info,
                         guint               time,
                         EShortcutBar   *shortcut_bar);
static void e_shortcut_bar_on_drag_data_received  (GtkWidget          *widget,
                           GdkDragContext     *context,
                           gint                x,
                           gint                y,
                           GtkSelectionData   *data,
                           guint               info,
                           guint               time,
                           EShortcutBar   *shortcut_bar);
static void e_shortcut_bar_on_drag_data_delete (GtkWidget          *widget,
                        GdkDragContext     *context,
                        EShortcutBar       *shortcut_bar);
static void e_shortcut_bar_stop_editing (GtkWidget *button,
                     EShortcutBar *shortcut_bar);
static GdkPixbuf* e_shortcut_bar_get_image_from_url (EShortcutBar *shortcut_bar,
                             gchar *item_url);
static GdkPixbuf* e_shortcut_bar_load_image (gchar *filename);


enum
{
  ITEM_SELECTED,
  LAST_SIGNAL
};

static guint e_shortcut_bar_signals[LAST_SIGNAL] = {0};

static EGroupBarClass *parent_class;


GtkType
e_shortcut_bar_get_type (void)
{
    static GtkType e_shortcut_bar_type = 0;

    if (!e_shortcut_bar_type){
        GtkTypeInfo e_shortcut_bar_info = {
            "EShortcutBar",
            sizeof (EShortcutBar),
            sizeof (EShortcutBarClass),
            (GtkClassInitFunc) e_shortcut_bar_class_init,
            (GtkObjectInitFunc) e_shortcut_bar_init,
            NULL, /* reserved 1 */
            NULL, /* reserved 2 */
            (GtkClassInitFunc) NULL
        };

        parent_class = gtk_type_class (e_group_bar_get_type ());
        e_shortcut_bar_type = gtk_type_unique (e_group_bar_get_type (),
                               &e_shortcut_bar_info);
    }

    return e_shortcut_bar_type;
}


static void
e_shortcut_bar_class_init (EShortcutBarClass *class)
{
    GtkObjectClass *object_class;
    GtkWidgetClass *widget_class;

    object_class = (GtkObjectClass *) class;
    widget_class = (GtkWidgetClass *) class;

    e_shortcut_bar_signals[ITEM_SELECTED] =
        gtk_signal_new ("item_selected",
                GTK_RUN_LAST | GTK_RUN_ACTION,
                object_class->type,
                GTK_SIGNAL_OFFSET (EShortcutBarClass,
                           selected_item),
                gtk_marshal_NONE__POINTER_INT_INT,
                GTK_TYPE_NONE, 3, GTK_TYPE_GDK_EVENT,
                GTK_TYPE_INT, GTK_TYPE_INT);

    gtk_object_class_add_signals (object_class, e_shortcut_bar_signals,
                      LAST_SIGNAL);

    /* Method override */
    object_class->destroy       = e_shortcut_bar_destroy;
}


static void
e_shortcut_bar_init (EShortcutBar *shortcut_bar)
{
    shortcut_bar->groups = g_array_new (FALSE, FALSE,
                        sizeof (EShortcutBarGroup));
}


GtkWidget *
e_shortcut_bar_new (void)
{
    GtkWidget *shortcut_bar;

    shortcut_bar = GTK_WIDGET (gtk_type_new (e_shortcut_bar_get_type ()));

    return shortcut_bar;
}


static void
e_shortcut_bar_destroy (GtkObject *object)
{
    EShortcutBar *shortcut_bar;

    shortcut_bar = E_SHORTCUT_BAR (object);

    GTK_OBJECT_CLASS (parent_class)->destroy (object);

    g_array_free (shortcut_bar->groups, TRUE);
}


gint
e_shortcut_bar_add_group (EShortcutBar *shortcut_bar, gchar *group_name)
{
    EShortcutBarGroup *group, tmp_group;
    gint group_num;
    GtkWidget *button, *label;

    g_return_val_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar), -1);
    g_return_val_if_fail (group_name != NULL, -1);

    group_num = shortcut_bar->groups->len;
    g_array_append_val (shortcut_bar->groups, tmp_group);

    group = &g_array_index (shortcut_bar->groups,
                EShortcutBarGroup, group_num);

    group->vscrolled_bar = e_vscrolled_bar_new (NULL);
    gtk_widget_show (group->vscrolled_bar);
    gtk_signal_connect (GTK_OBJECT (E_VSCROLLED_BAR (group->vscrolled_bar)->up_button), "pressed", GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing), shortcut_bar);
    gtk_signal_connect (GTK_OBJECT (E_VSCROLLED_BAR (group->vscrolled_bar)->down_button), "pressed", GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing), shortcut_bar);

    group->icon_bar = e_icon_bar_new ();
    gtk_widget_show (group->icon_bar);
    gtk_container_add (GTK_CONTAINER (group->vscrolled_bar),
               group->icon_bar);
    gtk_signal_connect (GTK_OBJECT (group->icon_bar), "item_selected",
                GTK_SIGNAL_FUNC (e_shortcut_bar_item_selected),
                shortcut_bar);
    gtk_signal_connect (GTK_OBJECT (group->icon_bar), "item_dragged",
                GTK_SIGNAL_FUNC (e_shortcut_bar_item_dragged),
                shortcut_bar);
    gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_get",
                GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_get),
                shortcut_bar);
    gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_received",
                GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_received),
                shortcut_bar);
    gtk_signal_connect (GTK_OBJECT (group->icon_bar), "drag_data_delete",
                GTK_SIGNAL_FUNC (e_shortcut_bar_on_drag_data_delete),
                shortcut_bar);

    e_shortcut_bar_set_canvas_style (shortcut_bar, group->icon_bar);

    button = gtk_button_new ();
    label = e_clipped_label_new (group_name);
    gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
    gtk_widget_show (label);
    gtk_container_add (GTK_CONTAINER (button), label);
    gtk_widget_show (button);
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (e_shortcut_bar_stop_editing),
                shortcut_bar);

    gtk_drag_dest_set (GTK_WIDGET (group->icon_bar),
               GTK_DEST_DEFAULT_ALL,
               target_table, n_targets,
               GDK_ACTION_COPY | GDK_ACTION_MOVE);
    gtk_drag_dest_set (GTK_WIDGET (button),
               GTK_DEST_DEFAULT_ALL,
               target_table, n_targets,
               GDK_ACTION_COPY | GDK_ACTION_MOVE);

    e_group_bar_add_group (E_GROUP_BAR (shortcut_bar),
                   group->vscrolled_bar, button, -1);


    return group_num;
}


void
e_shortcut_bar_remove_group (EShortcutBar    *shortcut_bar,
                 gint         group_num)
{
    e_group_bar_remove_group (E_GROUP_BAR (shortcut_bar), group_num);
    g_array_remove_index (shortcut_bar->groups, group_num);
}


gint
e_shortcut_bar_add_item (EShortcutBar *shortcut_bar, gint group_num,
             gchar *item_url, gchar *item_name)
{
    EShortcutBarGroup *group;
    GdkPixbuf *image;
    gint item_num;

    g_return_val_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar), -1);
    g_return_val_if_fail (group_num >= 0, -1);
    g_return_val_if_fail (group_num < shortcut_bar->groups->len, -1);
    g_return_val_if_fail (item_url != NULL, -1);
    g_return_val_if_fail (item_name != NULL, -1);

    image = e_shortcut_bar_get_image_from_url (shortcut_bar, item_url);
    group = &g_array_index (shortcut_bar->groups,
                EShortcutBarGroup, group_num);

    item_num = e_icon_bar_add_item (E_ICON_BAR (group->icon_bar),
                    image, item_name, -1);
    e_icon_bar_set_item_data_full (E_ICON_BAR (group->icon_bar), item_num,
                       g_strdup (item_url), g_free);
    return item_num;
}


void
e_shortcut_bar_remove_item  (EShortcutBar    *shortcut_bar,
                 gint         group_num,
                 gint         item_num)
{
    EShortcutBarGroup *group;

    g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar));
    g_return_if_fail (group_num >= 0);
    g_return_if_fail (group_num < shortcut_bar->groups->len);

    group = &g_array_index (shortcut_bar->groups,
                EShortcutBarGroup, group_num);

    e_icon_bar_remove_item (E_ICON_BAR (group->icon_bar), item_num);
}


static void
e_shortcut_bar_set_canvas_style (EShortcutBar *shortcut_bar,
                 GtkWidget *canvas)
{
        GtkRcStyle *rc_style;

        rc_style = gtk_rc_style_new ();

        rc_style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG | GTK_RC_BG;
        rc_style->fg[GTK_STATE_NORMAL].red   = 65535;
        rc_style->fg[GTK_STATE_NORMAL].green = 65535;
        rc_style->fg[GTK_STATE_NORMAL].blue  = 65535;

        rc_style->bg[GTK_STATE_NORMAL].red   = 32512;
        rc_style->bg[GTK_STATE_NORMAL].green = 32512;
        rc_style->bg[GTK_STATE_NORMAL].blue  = 32512;

        gtk_widget_modify_style (GTK_WIDGET (canvas), rc_style);
        gtk_rc_style_unref (rc_style);
}


void
e_shortcut_bar_set_view_type (EShortcutBar *shortcut_bar,
                  gint group_num,
                  EIconBarViewType view_type)
{
    EShortcutBarGroup *group;

    g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar));
    g_return_if_fail (group_num >= 0);
    g_return_if_fail (group_num < shortcut_bar->groups->len);

    group = &g_array_index (shortcut_bar->groups,
                EShortcutBarGroup, group_num);

    e_icon_bar_set_view_type (E_ICON_BAR (group->icon_bar), view_type);
}


static void
e_shortcut_bar_item_selected (EIconBar *icon_bar,
                  GdkEvent *event,
                  gint item_num,
                  EShortcutBar *shortcut_bar)
{
    gint group_num;

    group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar),
                           GTK_WIDGET (icon_bar)->parent);

    gtk_signal_emit (GTK_OBJECT (shortcut_bar),
             e_shortcut_bar_signals[ITEM_SELECTED],
             event, group_num, item_num);
}


static void
e_shortcut_bar_item_dragged (EIconBar *icon_bar,
                 GdkEvent *event,
                 gint item_num,
                 EShortcutBar *shortcut_bar)
{
    GtkTargetList *target_list;
    gint group_num;

    group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar),
                           GTK_WIDGET (icon_bar)->parent);

    /* FIXME: free somewhere - drag_end? */
    shortcut_bar->dragged_url = g_strdup (e_icon_bar_get_item_data (icon_bar, item_num));
    shortcut_bar->dragged_name = g_strdup (e_icon_bar_get_item_text (icon_bar, item_num));

    target_list = gtk_target_list_new (target_table, n_targets);
    gtk_drag_begin (GTK_WIDGET (icon_bar), target_list,
            GDK_ACTION_COPY | GDK_ACTION_MOVE,
            1, event);
    gtk_target_list_unref (target_list);
}


static void
e_shortcut_bar_on_drag_data_get (GtkWidget          *widget,
                 GdkDragContext     *context,
                 GtkSelectionData   *selection_data,
                 guint               info,
                 guint               time,
                 EShortcutBar       *shortcut_bar)
{
    gchar *data;

    if (info == TARGET_SHORTCUT) {
        data = g_strdup_printf ("%s%c%s", shortcut_bar->dragged_name,
                    '\0', shortcut_bar->dragged_url);
        gtk_selection_data_set (selection_data, selection_data->target,
                    8, data,
                    strlen (shortcut_bar->dragged_name)
                    + strlen (shortcut_bar->dragged_url)
                    + 2);
        g_free (data);
    }
}


static void  
e_shortcut_bar_on_drag_data_received  (GtkWidget          *widget,
                       GdkDragContext     *context,
                       gint                x,
                       gint                y,
                       GtkSelectionData   *data,
                       guint               info,
                       guint               time,
                       EShortcutBar   *shortcut_bar)
{
    EShortcutBarGroup *group;
    gchar *item_name, *item_url;
    EIconBar *icon_bar;
    GdkPixbuf *image;
    gint group_num, item_num;

    icon_bar = E_ICON_BAR (widget);

    if ((data->length >= 0) && (data->format == 8)
        && icon_bar->dragging_before_item_num != -1) {
        item_name = data->data;
        item_url = item_name + strlen (item_name) + 1;

        image = e_shortcut_bar_get_image_from_url (shortcut_bar,
                               item_url);

        group_num = e_group_bar_get_group_num (E_GROUP_BAR (shortcut_bar),
                               GTK_WIDGET (icon_bar)->parent);
        group = &g_array_index (shortcut_bar->groups,
                    EShortcutBarGroup, group_num);

        item_num = e_icon_bar_add_item (E_ICON_BAR (group->icon_bar), image, item_name, icon_bar->dragging_before_item_num);
        e_icon_bar_set_item_data_full (E_ICON_BAR (group->icon_bar),
                           item_num, g_strdup (item_url),
                           g_free);

        gtk_drag_finish (context, TRUE, TRUE, time);
        return;
    }
  
    gtk_drag_finish (context, FALSE, FALSE, time);
}


static void  
e_shortcut_bar_on_drag_data_delete (GtkWidget          *widget,
                    GdkDragContext     *context,
                    EShortcutBar       *shortcut_bar)
{
    EIconBar *icon_bar;

    icon_bar = E_ICON_BAR (widget);

    e_icon_bar_remove_item (icon_bar, icon_bar->dragged_item_num);
}


void
e_shortcut_bar_start_editing_item (EShortcutBar *shortcut_bar,
                   gint group_num,
                   gint item_num)
{
    EShortcutBarGroup *group;

    g_return_if_fail (E_IS_SHORTCUT_BAR (shortcut_bar));
    g_return_if_fail (group_num >= 0);
    g_return_if_fail (group_num < shortcut_bar->groups->len);

    group = &g_array_index (shortcut_bar->groups,
                EShortcutBarGroup, group_num);

    e_icon_bar_start_editing_item (E_ICON_BAR (group->icon_bar), item_num);
}


/* We stop editing any item when a scroll button is pressed. */
static void
e_shortcut_bar_stop_editing (GtkWidget *button,
                 EShortcutBar *shortcut_bar)
{
    EShortcutBarGroup *group;
    gint group_num;

    for (group_num = 0;
         group_num < shortcut_bar->groups->len;
         group_num++) {
        group = &g_array_index (shortcut_bar->groups,
                    EShortcutBarGroup, group_num);
        e_icon_bar_stop_editing_item (E_ICON_BAR (group->icon_bar),
                          TRUE);
    }
}


static GdkPixbuf *
e_shortcut_bar_get_image_from_url (EShortcutBar *shortcut_bar,
                   gchar *item_url)
{
    gchar *method_terminator;
    gint method_len, i;

    method_terminator = strchr (item_url, ':');
    if (method_terminator) {
        method_len = method_terminator - item_url + 1;

        /* Check if it is a builtin type. */
        for (i = 0; i < e_shortcut_bar_num_builtin_types; i++) {
            if (!strncmp (item_url, e_shortcut_bar_builtin_types[i].name, method_len)) {
                if (!e_shortcut_bar_builtin_types[i].image)
                    e_shortcut_bar_builtin_types[i].image = e_shortcut_bar_load_image (e_shortcut_bar_builtin_types[i].filename);
                return e_shortcut_bar_builtin_types[i].image;
            }
        }
    }

    if (!e_shortcut_bar_default_type_image_loaded) {
        e_shortcut_bar_default_type_image_loaded = TRUE;
        e_shortcut_bar_default_type_image = e_shortcut_bar_load_image (e_shortcut_bar_default_type_filename);
    }
    return e_shortcut_bar_default_type_image;
}


static GdkPixbuf *
e_shortcut_bar_load_image (gchar *filename)
{
    gchar *pathname;
    GdkPixbuf *image = NULL;

    pathname = gnome_pixmap_file (filename);
    if (pathname)
        image = gdk_pixbuf_new_from_file (pathname);
    else
        g_warning ("Couldn't find pixmap: %s", filename);

    return image;
}