Gimp/app/widgets/gimpeditor.c
Michael Natterer 59bd430526 make sure the button_box is always interted at the very bottom of the
2004-10-22  Michael Natterer  <mitch@gimp.org>

	* app/widgets/gimpeditor.c (gimp_editor_ensure_button_box): make
	sure the button_box is always interted at the very bottom of the
	editor.

	* app/widgets/gimpviewabledialog.c: changed the "description"
	property from CONSTRUCT_ONLY to CONSTRUCT.

	* app/widgets/gimpcolormapeditor.c: show the index of the edited
	color in the color dialog and use the correct icon. Replaced label
	"Hex triplet" by "HTML notation" to be consistent with the color
	dialog. Removed wrong 2 pixel border around the table below the
	preview.
2004-10-22 15:41:03 +00:00

733 lines
22 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpeditor.c
* Copyright (C) 2001-2004 Michael Natterer <mitch@gimp.org>
*
* 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.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "gimpdocked.h"
#include "gimpeditor.h"
#include "gimpdnd.h"
#include "gimpenumwidgets.h"
#include "gimpmenufactory.h"
#include "gimpuimanager.h"
#include "gimpwidgets-utils.h"
#define DEFAULT_CONTENT_SPACING 2
#define DEFAULT_BUTTON_SPACING 2
#define DEFAULT_BUTTON_ICON_SIZE GTK_ICON_SIZE_MENU
enum
{
PROP_0,
PROP_MENU_FACTORY,
PROP_MENU_IDENTIFIER,
PROP_UI_PATH,
PROP_POPUP_DATA
};
static void gimp_editor_class_init (GimpEditorClass *klass);
static void gimp_editor_init (GimpEditor *editor);
static void gimp_editor_docked_iface_init (GimpDockedInterface *docked_iface);
static GObject * gimp_editor_constructor (GType type,
guint n_params,
GObjectConstructParam *params);
static void gimp_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_editor_destroy (GtkObject *object);
static void gimp_editor_style_set (GtkWidget *widget,
GtkStyle *prev_style);
static GimpUIManager * gimp_editor_get_menu (GimpDocked *docked,
const gchar **ui_path,
gpointer *popup_data);
static GtkIconSize gimp_editor_ensure_button_box (GimpEditor *editor);
static GtkVBoxClass *parent_class = NULL;
GType
gimp_editor_get_type (void)
{
static GType type = 0;
if (! type)
{
static const GTypeInfo info =
{
sizeof (GimpEditorClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) gimp_editor_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpEditor),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_editor_init,
};
static const GInterfaceInfo docked_iface_info =
{
(GInterfaceInitFunc) gimp_editor_docked_iface_init,
NULL, /* iface_finalize */
NULL /* iface_data */
};
type = g_type_register_static (GTK_TYPE_VBOX,
"GimpEditor",
&info, 0);
g_type_add_interface_static (type, GIMP_TYPE_DOCKED,
&docked_iface_info);
}
return type;
}
static void
gimp_editor_class_init (GimpEditorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->constructor = gimp_editor_constructor;
object_class->set_property = gimp_editor_set_property;
object_class->get_property = gimp_editor_get_property;
gtk_object_class->destroy = gimp_editor_destroy;
widget_class->style_set = gimp_editor_style_set;
g_object_class_install_property (object_class, PROP_MENU_FACTORY,
g_param_spec_object ("menu-factory",
NULL, NULL,
GIMP_TYPE_MENU_FACTORY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_MENU_IDENTIFIER,
g_param_spec_string ("menu-identifier",
NULL, NULL,
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_UI_PATH,
g_param_spec_string ("ui-path",
NULL, NULL,
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_POPUP_DATA,
g_param_spec_pointer ("popup-data",
NULL, NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("content_spacing",
NULL, NULL,
0,
G_MAXINT,
DEFAULT_CONTENT_SPACING,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("button_spacing",
NULL, NULL,
0,
G_MAXINT,
DEFAULT_BUTTON_SPACING,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_enum ("button_icon_size",
NULL, NULL,
GTK_TYPE_ICON_SIZE,
DEFAULT_BUTTON_ICON_SIZE,
G_PARAM_READABLE));
}
static void
gimp_editor_init (GimpEditor *editor)
{
editor->menu_factory = NULL;
editor->menu_identifier = NULL;
editor->ui_manager = NULL;
editor->ui_path = NULL;
editor->popup_data = editor;
editor->button_box = NULL;
}
static void
gimp_editor_docked_iface_init (GimpDockedInterface *docked_iface)
{
docked_iface->get_menu = gimp_editor_get_menu;
}
static GObject *
gimp_editor_constructor (GType type,
guint n_params,
GObjectConstructParam *params)
{
GObject *object;
GimpEditor *editor;
object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
editor = GIMP_EDITOR (object);
if (! editor->popup_data)
editor->popup_data = editor;
if (editor->menu_factory && editor->menu_identifier)
{
editor->ui_manager =
gimp_menu_factory_manager_new (editor->menu_factory,
editor->menu_identifier,
editor->popup_data,
FALSE);
}
return object;
}
static void
gimp_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpEditor *editor = GIMP_EDITOR (object);
switch (property_id)
{
case PROP_MENU_FACTORY:
editor->menu_factory = (GimpMenuFactory *) g_value_dup_object (value);
break;
case PROP_MENU_IDENTIFIER:
editor->menu_identifier = g_value_dup_string (value);
break;
case PROP_UI_PATH:
editor->ui_path = g_value_dup_string (value);
break;
case PROP_POPUP_DATA:
editor->popup_data = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpEditor *editor = GIMP_EDITOR (object);
switch (property_id)
{
case PROP_MENU_FACTORY:
g_value_set_object (value, editor->menu_factory);
break;
case PROP_MENU_IDENTIFIER:
g_value_set_string (value, editor->menu_identifier);
break;
case PROP_UI_PATH:
g_value_set_string (value, editor->ui_path);
break;
case PROP_POPUP_DATA:
g_value_set_pointer (value, editor->popup_data);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_editor_destroy (GtkObject *object)
{
GimpEditor *editor = GIMP_EDITOR (object);
if (editor->menu_factory)
{
g_object_unref (editor->menu_factory);
editor->menu_factory = NULL;
}
if (editor->menu_identifier)
{
g_free (editor->menu_identifier);
editor->menu_identifier = NULL;
}
if (editor->ui_manager)
{
g_object_unref (editor->ui_manager);
editor->ui_manager = NULL;
}
if (editor->ui_path)
{
g_free (editor->ui_path);
editor->ui_path = NULL;
}
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
gimp_editor_style_set (GtkWidget *widget,
GtkStyle *prev_style)
{
GimpEditor *editor = GIMP_EDITOR (widget);
gint content_spacing;
if (GTK_WIDGET_CLASS (parent_class)->style_set)
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
gtk_widget_style_get (widget, "content_spacing", &content_spacing, NULL);
gtk_box_set_spacing (GTK_BOX (widget), content_spacing);
if (editor->button_box)
gimp_editor_set_box_style (editor, GTK_BOX (editor->button_box));
}
static GimpUIManager *
gimp_editor_get_menu (GimpDocked *docked,
const gchar **ui_path,
gpointer *popup_data)
{
GimpEditor *editor = GIMP_EDITOR (docked);
*ui_path = editor->ui_path;
*popup_data = editor->popup_data;
return editor->ui_manager;
}
GtkWidget *
gimp_editor_new (void)
{
GimpEditor *editor;
editor = g_object_new (GIMP_TYPE_EDITOR, NULL);
return GTK_WIDGET (editor);
}
void
gimp_editor_create_menu (GimpEditor *editor,
GimpMenuFactory *menu_factory,
const gchar *menu_identifier,
const gchar *ui_path,
gpointer popup_data)
{
g_return_if_fail (GIMP_IS_EDITOR (editor));
g_return_if_fail (GIMP_IS_MENU_FACTORY (menu_factory));
g_return_if_fail (menu_identifier != NULL);
g_return_if_fail (ui_path != NULL);
if (editor->menu_factory)
g_object_unref (editor->menu_factory);
editor->menu_factory = g_object_ref (menu_factory);
if (editor->ui_manager)
g_object_unref (editor->ui_manager);
editor->ui_manager = gimp_menu_factory_manager_new (menu_factory,
menu_identifier,
popup_data,
FALSE);
if (editor->ui_path)
g_free (editor->ui_path);
editor->ui_path = g_strdup (ui_path);
editor->popup_data = popup_data;
}
gboolean
gimp_editor_popup_menu (GimpEditor *editor,
GimpMenuPositionFunc position_func,
gpointer position_data)
{
g_return_val_if_fail (GIMP_IS_EDITOR (editor), FALSE);
if (editor->ui_manager && editor->ui_path)
{
gimp_ui_manager_update (editor->ui_manager, editor->popup_data);
gimp_ui_manager_ui_popup (editor->ui_manager, editor->ui_path,
GTK_WIDGET (editor),
position_func, position_data,
NULL, NULL);
return TRUE;
}
return FALSE;
}
GtkWidget *
gimp_editor_add_button (GimpEditor *editor,
const gchar *stock_id,
const gchar *tooltip,
const gchar *help_id,
GCallback callback,
GCallback extended_callback,
gpointer callback_data)
{
GtkWidget *button;
GtkWidget *image;
GtkIconSize button_icon_size;
g_return_val_if_fail (GIMP_IS_EDITOR (editor), NULL);
g_return_val_if_fail (stock_id != NULL, NULL);
button_icon_size = gimp_editor_ensure_button_box (editor);
button = gimp_button_new ();
gtk_box_pack_start (GTK_BOX (editor->button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
if (tooltip || help_id)
gimp_help_set_help_data (button, tooltip, help_id);
if (callback)
g_signal_connect (button, "clicked",
callback,
callback_data);
if (extended_callback)
g_signal_connect (button, "extended_clicked",
extended_callback,
callback_data);
image = gtk_image_new_from_stock (stock_id, button_icon_size);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
return button;
}
GtkWidget *
gimp_editor_add_stock_box (GimpEditor *editor,
GType enum_type,
const gchar *stock_prefix,
GCallback callback,
gpointer callback_data)
{
GtkWidget *hbox;
GtkWidget *first_button;
GtkIconSize button_icon_size;
GList *children;
GList *list;
g_return_val_if_fail (GIMP_IS_EDITOR (editor), NULL);
g_return_val_if_fail (g_type_is_a (enum_type, G_TYPE_ENUM), NULL);
g_return_val_if_fail (stock_prefix != NULL, NULL);
button_icon_size = gimp_editor_ensure_button_box (editor);
hbox = gimp_enum_stock_box_new (enum_type, stock_prefix, button_icon_size,
callback, callback_data,
&first_button);
children = gtk_container_get_children (GTK_CONTAINER (hbox));
for (list = children; list; list = g_list_next (list))
{
GtkWidget *button = list->data;
g_object_ref (button);
gtk_container_remove (GTK_CONTAINER (hbox), button);
gtk_box_pack_start (GTK_BOX (editor->button_box), button,
TRUE, TRUE, 0);
g_object_unref (button);
}
g_list_free (children);
gtk_object_sink (GTK_OBJECT (hbox));
return first_button;
}
typedef struct _ExtendedAction ExtendedAction;
struct _ExtendedAction
{
GdkModifierType mod_mask;
GtkAction *action;
};
static void
gimp_editor_button_extended_actions_free (GList *list)
{
g_list_foreach (list, (GFunc) g_free, NULL);
g_list_free (list);
}
static void
gimp_editor_button_extended_clicked (GtkWidget *button,
GdkModifierType mask,
gpointer data)
{
GList *extended = g_object_get_data (G_OBJECT (button), "extended-actions");
GList *list;
for (list = extended; list; list = g_list_next (list))
{
ExtendedAction *ext = list->data;
if ((ext->mod_mask & mask) == ext->mod_mask &&
gtk_action_get_sensitive (ext->action))
{
gtk_action_activate (ext->action);
break;
}
}
}
GtkWidget *
gimp_editor_add_action_button (GimpEditor *editor,
const gchar *group_name,
const gchar *action_name,
...)
{
GimpActionGroup *group;
GtkAction *action;
GtkWidget *button;
GtkWidget *old_child;
GtkWidget *image;
GtkIconSize button_icon_size;
gchar *stock_id;
gchar *tooltip;
const gchar *help_id;
GList *extended = NULL;
va_list args;
g_return_val_if_fail (GIMP_IS_EDITOR (editor), NULL);
g_return_val_if_fail (action_name != NULL, NULL);
g_return_val_if_fail (editor->ui_manager != NULL, NULL);
group = gimp_ui_manager_get_action_group (editor->ui_manager, group_name);
g_return_val_if_fail (group != NULL, NULL);
action = gtk_action_group_get_action (GTK_ACTION_GROUP (group),
action_name);
g_return_val_if_fail (action != NULL, NULL);
button_icon_size = gimp_editor_ensure_button_box (editor);
if (GTK_IS_TOGGLE_ACTION (action))
{
button = gtk_toggle_button_new ();
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
}
else
{
button = gimp_button_new ();
}
gtk_action_connect_proxy (action, button);
gtk_box_pack_start (GTK_BOX (editor->button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
g_object_get (action,
"stock-id", &stock_id,
"tooltip", &tooltip,
NULL);
help_id = g_object_get_qdata (G_OBJECT (action), GIMP_HELP_ID);
old_child = gtk_bin_get_child (GTK_BIN (button));
if (old_child)
gtk_container_remove (GTK_CONTAINER (button), old_child);
image = gtk_image_new_from_stock (stock_id, button_icon_size);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_free (stock_id);
va_start (args, action_name);
action_name = va_arg (args, const gchar *);
while (action_name)
{
GdkModifierType mod_mask;
mod_mask = va_arg (args, GdkModifierType);
action = gtk_action_group_get_action (GTK_ACTION_GROUP (group),
action_name);
if (action && mod_mask)
{
ExtendedAction *ext = g_new0 (ExtendedAction, 1);
ext->mod_mask = mod_mask;
ext->action = action;
extended = g_list_prepend (extended, ext);
if (tooltip)
{
gchar *ext_tooltip;
g_object_get (action, "tooltip", &ext_tooltip, NULL);
if (ext_tooltip)
{
gchar *tmp;
tmp = g_strconcat (tooltip, "\n",
gimp_get_mod_string (mod_mask), " ",
ext_tooltip, NULL);
g_free (tooltip);
tooltip = tmp;
}
}
}
action_name = va_arg (args, const gchar *);
}
va_end (args);
if (extended)
{
g_object_set_data_full (G_OBJECT (button), "extended-actions", extended,
(GDestroyNotify) gimp_editor_button_extended_actions_free);
g_signal_connect (button, "extended_clicked",
G_CALLBACK (gimp_editor_button_extended_clicked),
NULL);
}
if (tooltip || help_id)
gimp_help_set_help_data (button, tooltip, help_id);
g_free (tooltip);
return button;
}
void
gimp_editor_set_box_style (GimpEditor *editor,
GtkBox *box)
{
GtkIconSize button_icon_size;
gint button_spacing;
GList *children;
GList *list;
g_return_if_fail (GIMP_IS_EDITOR (editor));
g_return_if_fail (GTK_IS_BOX (box));
gtk_widget_style_get (GTK_WIDGET (editor),
"button_icon_size", &button_icon_size,
"button_spacing", &button_spacing,
NULL);
gtk_box_set_spacing (box, button_spacing);
children = gtk_container_get_children (GTK_CONTAINER (box));
for (list = children; list; list = g_list_next (list))
{
if (GTK_IS_BUTTON (list->data))
{
GtkWidget *child;
child = gtk_bin_get_child (GTK_BIN (list->data));
if (GTK_IS_IMAGE (child))
{
gchar *stock_id;
gtk_image_get_stock (GTK_IMAGE (child), &stock_id, NULL);
gtk_image_set_from_stock (GTK_IMAGE (child),
stock_id, button_icon_size);
}
}
}
g_list_free (children);
}
/* private functions */
static GtkIconSize
gimp_editor_ensure_button_box (GimpEditor *editor)
{
GtkIconSize button_icon_size;
gint button_spacing;
gtk_widget_style_get (GTK_WIDGET (editor),
"button_icon_size", &button_icon_size,
"button_spacing", &button_spacing,
NULL);
if (! editor->button_box)
{
editor->button_box = gtk_hbox_new (TRUE, button_spacing);
gtk_box_pack_end (GTK_BOX (editor), editor->button_box, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (editor), editor->button_box, 0);
gtk_widget_show (editor->button_box);
}
return button_icon_size;
}