home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimppatheditor.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-19  |  14.9 KB  |  478 lines

  1. /* LIBGIMP - The GIMP Library 
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimppatheditor.c
  5.  * Copyright (C) 1999 Michael Natterer <mitch@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful, 
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include <string.h>
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include "gimppatheditor.h"
  28.  
  29. #include "libgimp/gimpfileselection.h"
  30. #include "libgimp/gimpwidgets.h"
  31.  
  32. #include "pixmaps/new.xpm"
  33. #include "pixmaps/delete.xpm"
  34. #include "pixmaps/raise.xpm"
  35. #include "pixmaps/lower.xpm"
  36.  
  37.  
  38. /*  forward declaration  */
  39. static void gimp_path_editor_select_callback   (GtkWidget *widget,
  40.                         gpointer   data);
  41. static void gimp_path_editor_deselect_callback (GtkWidget *widget,
  42.                         gpointer   data);
  43. static void gimp_path_editor_new_callback      (GtkWidget *widget,
  44.                         gpointer   data);
  45. static void gimp_path_editor_move_callback     (GtkWidget *widget,
  46.                         gpointer   data);
  47. static void gimp_path_editor_filesel_callback  (GtkWidget *widget,
  48.                         gpointer   data);
  49. static void gimp_path_editor_delete_callback   (GtkWidget *widget,
  50.                         gpointer   data);
  51.  
  52. enum
  53. {
  54.   PATH_CHANGED,
  55.   LAST_SIGNAL
  56. };
  57.  
  58. static guint gimp_path_editor_signals[LAST_SIGNAL] = { 0 };
  59.  
  60. static GtkVBoxClass *parent_class = NULL;
  61.  
  62. static void
  63. gimp_path_editor_class_init (GimpPathEditorClass *class)
  64. {
  65.   GtkObjectClass *object_class;
  66.  
  67.   object_class = (GtkObjectClass *) class;
  68.  
  69.   parent_class = gtk_type_class (gtk_vbox_get_type ());
  70.  
  71.   gimp_path_editor_signals[PATH_CHANGED] = 
  72.     gtk_signal_new ("path_changed",
  73.             GTK_RUN_FIRST,
  74.             object_class->type,
  75.             GTK_SIGNAL_OFFSET (GimpPathEditorClass,
  76.                        path_changed),
  77.             gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  78.  
  79.   gtk_object_class_add_signals (object_class, gimp_path_editor_signals, 
  80.                 LAST_SIGNAL);
  81.  
  82.   class->path_changed = NULL;
  83. }
  84.  
  85. static void
  86. gimp_path_editor_init (GimpPathEditor *gpe)
  87. {
  88.   GtkWidget *button_box;
  89.   GtkWidget *button;
  90.   GtkWidget *scrolled_window;
  91.  
  92.   gpe->file_selection  = NULL;
  93.   gpe->selected_item   = NULL;
  94.   gpe->number_of_items = 0;
  95.  
  96.   gpe->upper_hbox = gtk_hbox_new (FALSE, 2);
  97.   gtk_box_pack_start (GTK_BOX (gpe), gpe->upper_hbox, FALSE, TRUE, 0);
  98.   gtk_widget_show (gpe->upper_hbox);
  99.  
  100.   button_box = gtk_hbox_new (TRUE, 0);
  101.   gtk_box_pack_start (GTK_BOX (gpe->upper_hbox), button_box, FALSE, TRUE, 0);
  102.   gtk_widget_show (button_box);
  103.  
  104.   gpe->new_button = button = gimp_pixmap_button_new (new_xpm, NULL);
  105.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  106.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  107.               GTK_SIGNAL_FUNC (gimp_path_editor_new_callback),
  108.               gpe);
  109.   gtk_widget_show (button);
  110.  
  111.   gpe->up_button = button = gimp_pixmap_button_new (raise_xpm, NULL);
  112.   gtk_widget_set_sensitive (button, FALSE);
  113.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  114.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  115.               GTK_SIGNAL_FUNC (gimp_path_editor_move_callback),
  116.               gpe);
  117.   gtk_widget_show (button);
  118.  
  119.   gpe->down_button = button = gimp_pixmap_button_new (lower_xpm, NULL);
  120.   gtk_widget_set_sensitive (button, FALSE);
  121.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  122.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  123.               GTK_SIGNAL_FUNC (gimp_path_editor_move_callback),
  124.               gpe);
  125.   gtk_widget_show (button);
  126.  
  127.   gpe->delete_button = button = gimp_pixmap_button_new (delete_xpm, NULL);
  128.   gtk_widget_set_sensitive (button, FALSE);
  129.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  130.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  131.               GTK_SIGNAL_FUNC (gimp_path_editor_delete_callback),
  132.               gpe);
  133.   gtk_widget_show (button);
  134.  
  135.   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  136.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
  137.                                   GTK_POLICY_AUTOMATIC,
  138.                                   GTK_POLICY_ALWAYS);
  139.   gtk_box_pack_start (GTK_BOX (gpe), scrolled_window, TRUE, TRUE, 2);
  140.   gtk_widget_show (scrolled_window);
  141.  
  142.   gpe->dir_list = gtk_list_new ();
  143.   gtk_list_set_selection_mode (GTK_LIST (gpe->dir_list), GTK_SELECTION_SINGLE);
  144.   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
  145.                      gpe->dir_list);
  146.   gtk_widget_show (gpe->dir_list);
  147. }
  148.  
  149. GtkType
  150. gimp_path_editor_get_type (void)
  151. {
  152.   static GtkType gpe_type = 0;
  153.  
  154.   if (!gpe_type)
  155.     {
  156.       GtkTypeInfo gpe_info =
  157.       {
  158.     "GimpPathEditor",
  159.     sizeof (GimpPathEditor),
  160.     sizeof (GimpPathEditorClass),
  161.     (GtkClassInitFunc) gimp_path_editor_class_init,
  162.     (GtkObjectInitFunc) gimp_path_editor_init,
  163.     /* reserved_1 */ NULL,
  164.     /* reserved_2 */ NULL,
  165.         (GtkClassInitFunc) NULL
  166.       };
  167.  
  168.       gpe_type = gtk_type_unique (gtk_vbox_get_type (), &gpe_info);
  169.     }
  170.   
  171.   return gpe_type;
  172. }
  173.  
  174. /**
  175.  * gimp_path_editor_new:
  176.  * @filesel_title: The title of the #GtkFileSelection dialog which can be
  177.  *                 popped up by the attached #GimpFileSelection.
  178.  * @path: The initial search path.
  179.  *
  180.  * Creates a new #GimpPathEditor widget.
  181.  *
  182.  * The elements of the initial search path must be separated with the
  183.  * #G_SEARCHPATH_SEPARATOR character.
  184.  *
  185.  * Returns: A pointer to the new #GimpPathEditor widget.
  186.  **/
  187. GtkWidget *
  188. gimp_path_editor_new (const gchar *filesel_title,
  189.               const gchar *path)
  190. {
  191.   GimpPathEditor *gpe;
  192.   GtkWidget      *list_item;
  193.   GList          *directory_list;
  194.   gchar          *directory;
  195.   gchar          *mypath;
  196.  
  197.   g_return_val_if_fail ((filesel_title != NULL), NULL);
  198.   g_return_val_if_fail ((path != NULL), NULL);
  199.  
  200.   gpe = gtk_type_new (gimp_path_editor_get_type ());
  201.  
  202.   gpe->file_selection = gimp_file_selection_new (filesel_title, "", TRUE, TRUE);
  203.   gtk_widget_set_sensitive (gpe->file_selection, FALSE);
  204.   gtk_box_pack_start (GTK_BOX (gpe->upper_hbox), gpe->file_selection,
  205.               TRUE, TRUE, 0);
  206.   gtk_signal_connect (GTK_OBJECT (gpe->file_selection), "filename_changed",
  207.               GTK_SIGNAL_FUNC (gimp_path_editor_filesel_callback),
  208.               gpe);
  209.   gtk_widget_show (gpe->file_selection);
  210.  
  211.   directory_list = NULL;
  212.   directory      = mypath = g_strdup (path);
  213.  
  214.   /*  split up the path  */
  215.   while (strlen (directory))
  216.     {
  217.       gchar *current_dir;
  218.       gchar *next_separator;
  219.  
  220.       next_separator = strchr (directory, G_SEARCHPATH_SEPARATOR);
  221.       if (next_separator != NULL)
  222.     *next_separator = '\0';
  223.  
  224.       current_dir = g_strdup (directory);
  225.  
  226.       list_item = gtk_list_item_new_with_label (current_dir);
  227.       gtk_object_set_data_full (GTK_OBJECT (list_item), "gimp_path_editor",
  228.                 current_dir,
  229.                 (GtkDestroyNotify) g_free);
  230.       directory_list = g_list_append (directory_list, list_item);
  231.       gtk_signal_connect (GTK_OBJECT (list_item), "select",
  232.               GTK_SIGNAL_FUNC (gimp_path_editor_select_callback),
  233.               gpe);
  234.       gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
  235.               GTK_SIGNAL_FUNC (gimp_path_editor_deselect_callback),
  236.               gpe);
  237.       gtk_widget_show (list_item);
  238.       gpe->number_of_items++;
  239.  
  240.       if (next_separator != NULL)
  241.     directory = next_separator + 1;
  242.       else
  243.     break;
  244.     }
  245.  
  246.   g_free (mypath);
  247.  
  248.   if (directory_list)
  249.     gtk_list_append_items (GTK_LIST (gpe->dir_list), directory_list);
  250.  
  251.   return GTK_WIDGET (gpe);
  252. }
  253.  
  254. /**
  255.  * gimp_path_editor_get_path:
  256.  * @gpe: The path editor you want to get the search path from.
  257.  *
  258.  * The elements of the returned search path string are separated with the
  259.  * #G_SEARCHPATH_SEPARATOR character.
  260.  *
  261.  * Note that you have to g_free() the returned string.
  262.  *
  263.  * Returns: The search path the user has selected in the path editor.
  264.  **/
  265. gchar *
  266. gimp_path_editor_get_path (GimpPathEditor *gpe)
  267. {
  268.   GList *list;
  269.   gchar *path = NULL;
  270.  
  271.   g_return_val_if_fail (gpe != NULL, g_strdup (""));
  272.   g_return_val_if_fail (GIMP_IS_PATH_EDITOR (gpe), g_strdup (""));
  273.  
  274.   for (list = GTK_LIST (gpe->dir_list)->children; list; list = list->next)
  275.     {
  276.       if (path == NULL)
  277.     {
  278.       path =
  279.         g_strdup ((gchar *) gtk_object_get_data (GTK_OBJECT (list->data),
  280.                              "gimp_path_editor"));
  281.     }
  282.       else
  283.     {
  284.       gchar *newpath;
  285.  
  286.       newpath =
  287.         g_strconcat (path,
  288.              G_SEARCHPATH_SEPARATOR_S,
  289.              (gchar *) gtk_object_get_data (GTK_OBJECT (list->data),
  290.                             "gimp_path_editor"),
  291.              NULL);
  292.  
  293.       g_free (path);
  294.       path = newpath;
  295.     }
  296.     }
  297.  
  298.   return path;
  299. }
  300.  
  301. static void
  302. gimp_path_editor_select_callback (GtkWidget *widget,
  303.                   gpointer   data)
  304. {
  305.   GimpPathEditor *gpe;
  306.   gint            pos;
  307.   gchar          *directory;
  308.  
  309.   gpe = GIMP_PATH_EDITOR (data);
  310.   directory = (gchar *) gtk_object_get_data (GTK_OBJECT (widget),
  311.                          "gimp_path_editor");
  312.  
  313.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  314.   gimp_file_selection_set_filename (GIMP_FILE_SELECTION (gpe->file_selection),
  315.                     directory);
  316.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  317.   gpe->selected_item = widget;
  318.  
  319.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  320.  
  321.   gtk_widget_set_sensitive (gpe->delete_button, TRUE);
  322.   gtk_widget_set_sensitive (gpe->up_button, (pos > 0));
  323.   gtk_widget_set_sensitive (gpe->down_button,
  324.                 (pos < (gpe->number_of_items - 1)));
  325.   gtk_widget_set_sensitive (gpe->file_selection, TRUE);
  326. }
  327.  
  328. /*  the selected directory may never be deselected except by the 'new'
  329.  *  button, so catch the "deselect" signal and reselect it
  330.  */
  331. static void
  332. gimp_path_editor_deselect_callback (GtkWidget *widget,
  333.                     gpointer   data)
  334. {
  335.   GimpPathEditor *gpe;
  336.  
  337.   gpe = GIMP_PATH_EDITOR (data);
  338.  
  339.   if (widget != gpe->selected_item)
  340.     return;
  341.  
  342.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  343.   gtk_list_select_child (GTK_LIST (gpe->dir_list), gpe->selected_item);
  344.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  345. }
  346.  
  347. static void
  348. gimp_path_editor_new_callback (GtkWidget *widget,
  349.                    gpointer   data)
  350. {
  351.   GimpPathEditor *gpe;
  352.  
  353.   gpe = GIMP_PATH_EDITOR (data);
  354.  
  355.   if (gpe->selected_item)
  356.     {
  357.       gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  358.       gtk_list_unselect_child (GTK_LIST (gpe->dir_list), gpe->selected_item);
  359.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  360.     }
  361.   gpe->selected_item = NULL;
  362.  
  363.   gtk_widget_set_sensitive (gpe->delete_button, FALSE);
  364.   gtk_widget_set_sensitive (gpe->up_button, FALSE);
  365.   gtk_widget_set_sensitive (gpe->down_button, FALSE);
  366.   gtk_widget_set_sensitive (gpe->file_selection, TRUE);
  367.  
  368.   gtk_editable_set_position
  369.     (GTK_EDITABLE (GIMP_FILE_SELECTION (gpe->file_selection)->entry), -1);
  370.   gtk_widget_grab_focus
  371.     (GTK_WIDGET (GIMP_FILE_SELECTION (gpe->file_selection)->entry));
  372. }
  373.  
  374. static void
  375. gimp_path_editor_move_callback (GtkWidget *widget,
  376.                 gpointer   data)
  377. {
  378.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  379.   GList          *move_list = NULL;
  380.   gint            pos;
  381.   gint            distance;
  382.  
  383.   if (gpe->selected_item == NULL)
  384.     return;
  385.  
  386.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  387.   distance = (widget == gpe->up_button) ? - 1 : 1;
  388.   move_list = g_list_append (move_list, gpe->selected_item);
  389.  
  390.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  391.   gtk_list_remove_items_no_unref (GTK_LIST (gpe->dir_list), move_list);
  392.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  393.   gtk_list_insert_items (GTK_LIST (gpe->dir_list), move_list, pos + distance);
  394.   gtk_list_select_item (GTK_LIST (gpe->dir_list), pos + distance);
  395.  
  396.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  397. }
  398.  
  399. static void
  400. gimp_path_editor_delete_callback (GtkWidget *widget,
  401.                   gpointer   data)
  402. {
  403.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  404.   GList          *delete_list = NULL;
  405.   gint            pos;
  406.  
  407.   if (gpe->selected_item == NULL)
  408.     return;
  409.  
  410.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  411.   delete_list = g_list_append (delete_list, gpe->selected_item);
  412.  
  413.   gtk_list_remove_items (GTK_LIST (gpe->dir_list), delete_list);
  414.   gpe->number_of_items--;
  415.  
  416.   if (gpe->number_of_items == 0)
  417.     {
  418.       gpe->selected_item = NULL;
  419.       gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  420.       gimp_file_selection_set_filename (GIMP_FILE_SELECTION (gpe->file_selection), "");
  421.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  422.       gtk_widget_set_sensitive (gpe->delete_button, FALSE);
  423.       gtk_widget_set_sensitive (gpe->file_selection, FALSE);
  424.  
  425.       return;
  426.     }
  427.  
  428.   if ((pos == gpe->number_of_items) && (pos > 0))
  429.     pos--;
  430.   gtk_list_select_item (GTK_LIST (gpe->dir_list), pos);
  431.  
  432.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  433. }
  434.  
  435. static void
  436. gimp_path_editor_filesel_callback (GtkWidget *widget,
  437.                    gpointer   data)
  438. {
  439.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  440.   GList          *append_list = NULL;
  441.   GtkWidget      *list_item = NULL;
  442.   gchar          *directory;
  443.  
  444.   directory = gimp_file_selection_get_filename (GIMP_FILE_SELECTION (widget));
  445.   if (strcmp (directory, "") == 0)
  446.     return;
  447.  
  448.   if (gpe->selected_item == NULL)
  449.     {
  450.       list_item = gtk_list_item_new_with_label (directory);
  451.       gtk_object_set_data_full (GTK_OBJECT (list_item), "gimp_path_editor",
  452.                 directory,
  453.                 (GtkDestroyNotify) g_free);
  454.       append_list = g_list_append (append_list, list_item);
  455.       gtk_signal_connect (GTK_OBJECT (list_item), "select",
  456.               GTK_SIGNAL_FUNC (gimp_path_editor_select_callback),
  457.               gpe);
  458.       gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
  459.               GTK_SIGNAL_FUNC (gimp_path_editor_deselect_callback),
  460.               gpe);
  461.       gtk_widget_show (list_item);
  462.       gpe->number_of_items++;
  463.       gtk_list_append_items (GTK_LIST (gpe->dir_list), append_list);
  464.       gtk_list_select_item (GTK_LIST (gpe->dir_list), gpe->number_of_items - 1);
  465.     }
  466.   else
  467.     {
  468.       gtk_label_set_text (GTK_LABEL (GTK_BIN (gpe->selected_item)->child),
  469.               directory);
  470.       gtk_object_set_data_full (GTK_OBJECT (gpe->selected_item),
  471.                 "gimp_path_editor",
  472.                 directory,
  473.                 (GtkDestroyNotify) g_free);
  474.     }
  475.  
  476.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  477. }
  478.