From d1c99beeb4e8b6176592dddb579b116d3cee48d7 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Sat, 22 Mar 2003 16:26:11 +0000 Subject: [PATCH] allow to create a GimpContainerEditor without a popup menu. 2003-03-22 Michael Natterer * app/widgets/gimpcontainereditor.c: allow to create a GimpContainerEditor without a popup menu. * app/widgets/gimpcellrendererviewable.c: free the event we got from gdk_get_current_event(). * app/widgets/gimpcontainerview.c: check view->hash_table for being non-NULL before using it. Be prepared to be destroyed by as a result of calling gimp_context_set_foo(view->context, foo). * app/widgets/gimpcontainertreeview.[ch]: added tree_view->editable_cells and handle *all* mouse clicks in gimp_container_tree_view_button_press() (by returning TRUE). Start editing on double-click only. Use gtk_tree_view_set_cursor() instead of gtk_tree_selection_select_path() to avoid selected/focus confusion when the focus enters the widget. Be prepeared to be destroyed as a result of item selection. * app/widgets/Makefile.am * app/widgets/widgets-types.h * app/widgets/gimpcontainerpopup.[ch]: new GtkWindow derived widget which pops up a selection of any GimpContainer/GimpContext combo. * app/widgets/gimpdatafactoryview.c * app/widgets/gimpitemtreeview.c: add the name cell to tree_view->editable_cells so it becomes editable. * app/tools/gimpblendoptions.c * app/tools/paint_options.c: use the new container popup for selecting brushes and gradients. --- ChangeLog | 34 +++ app/tools/gimpblendoptions.c | 20 +- app/tools/gimppaintoptions-gui.c | 22 +- app/tools/paint_options.c | 22 +- app/widgets/Makefile.am | 2 + app/widgets/gimpcellrendererviewable.c | 23 +- app/widgets/gimpcontainereditor.c | 10 +- app/widgets/gimpcontainerpopup.c | 397 +++++++++++++++++++++++++ app/widgets/gimpcontainerpopup.h | 67 +++++ app/widgets/gimpcontainertreeview.c | 79 +++-- app/widgets/gimpcontainertreeview.h | 1 + app/widgets/gimpcontainerview.c | 68 +++-- app/widgets/gimpdatafactoryview.c | 3 + app/widgets/gimpitemtreeview.c | 3 + app/widgets/widgets-types.h | 1 + 15 files changed, 665 insertions(+), 87 deletions(-) create mode 100644 app/widgets/gimpcontainerpopup.c create mode 100644 app/widgets/gimpcontainerpopup.h diff --git a/ChangeLog b/ChangeLog index 98b80d5aec..5965c42dec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2003-03-22 Michael Natterer + + * app/widgets/gimpcontainereditor.c: allow to create a + GimpContainerEditor without a popup menu. + + * app/widgets/gimpcellrendererviewable.c: free the event we + got from gdk_get_current_event(). + + * app/widgets/gimpcontainerview.c: check view->hash_table for + being non-NULL before using it. Be prepared to be destroyed by as + a result of calling gimp_context_set_foo(view->context, foo). + + * app/widgets/gimpcontainertreeview.[ch]: added + tree_view->editable_cells and handle *all* mouse clicks in + gimp_container_tree_view_button_press() (by returning TRUE). Start + editing on double-click only. Use gtk_tree_view_set_cursor() + instead of gtk_tree_selection_select_path() to avoid + selected/focus confusion when the focus enters the widget. Be + prepeared to be destroyed as a result of item selection. + + * app/widgets/Makefile.am + * app/widgets/widgets-types.h + * app/widgets/gimpcontainerpopup.[ch]: new GtkWindow derived + widget which pops up a selection of any GimpContainer/GimpContext + combo. + + * app/widgets/gimpdatafactoryview.c + * app/widgets/gimpitemtreeview.c: add the name cell to + tree_view->editable_cells so it becomes editable. + + * app/tools/gimpblendoptions.c + * app/tools/paint_options.c: use the new container popup for + selecting brushes and gradients. + 2003-03-22 Jakub Steiner * themes/Default/images/stock-linked-12.png: diff --git a/app/tools/gimpblendoptions.c b/app/tools/gimpblendoptions.c index 2323b10c75..42a05c9f4b 100644 --- a/app/tools/gimpblendoptions.c +++ b/app/tools/gimpblendoptions.c @@ -27,8 +27,10 @@ #include "config/gimpconfig-params.h" #include "core/gimp.h" +#include "core/gimpdatafactory.h" #include "core/gimptoolinfo.h" +#include "widgets/gimpcontainerpopup.h" #include "widgets/gimpdialogfactory.h" #include "widgets/gimpdock.h" #include "widgets/gimppropwidgets.h" @@ -67,7 +69,7 @@ static void gradient_type_notify (GimpBlendOptions *options, GParamSpec *pspec, GtkWidget *repeat_menu); static void blend_options_gradient_clicked (GtkWidget *widget, - gpointer data); + GimpContext *context); static GimpPaintOptionsClass *parent_class = NULL; @@ -263,7 +265,7 @@ gimp_blend_options_gui (GimpToolOptions *tool_options) g_signal_connect (button, "clicked", G_CALLBACK (blend_options_gradient_clicked), - NULL); + tool_options); /* the gradient type menu */ optionmenu = gimp_prop_enum_option_menu_new (config, "gradient-type", 0, 0); @@ -322,16 +324,14 @@ gimp_blend_options_gui (GimpToolOptions *tool_options) } static void -blend_options_gradient_clicked (GtkWidget *widget, - gpointer data) +blend_options_gradient_clicked (GtkWidget *widget, + GimpContext *context) { - GtkWidget *toplevel; + GtkWidget *popup; - toplevel = gtk_widget_get_toplevel (widget); - - if (GIMP_IS_DOCK (toplevel)) - gimp_dialog_factory_dialog_raise (GIMP_DOCK (toplevel)->dialog_factory, - "gimp-gradient-list", -1); + popup = gimp_container_popup_new (context->gimp->gradient_factory->container, + context); + gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup), widget); } static void diff --git a/app/tools/gimppaintoptions-gui.c b/app/tools/gimppaintoptions-gui.c index 1af4b1ada4..de6f6696ec 100644 --- a/app/tools/gimppaintoptions-gui.c +++ b/app/tools/gimppaintoptions-gui.c @@ -28,10 +28,12 @@ #include "config/gimpconfig.h" #include "core/gimp.h" +#include "core/gimpdatafactory.h" #include "core/gimptoolinfo.h" #include "paint/gimppaintoptions.h" +#include "widgets/gimpcontainerpopup.h" #include "widgets/gimpdialogfactory.h" #include "widgets/gimpdock.h" #include "widgets/gimppropwidgets.h" @@ -65,8 +67,8 @@ static GtkWidget * gradient_options_gui (GimpGradientOptions *gradient, GType tool_type, GtkWidget *incremental_toggle); -static void paint_options_brush_clicked (GtkWidget *widget, - gpointer data); +static void paint_options_brush_clicked (GtkWidget *widget, + GimpContext *context); GtkWidget * @@ -134,7 +136,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) g_signal_connect (button, "clicked", G_CALLBACK (paint_options_brush_clicked), - NULL); + context); } /* a separator after the common paint options */ @@ -411,14 +413,12 @@ gradient_options_gui (GimpGradientOptions *gradient, } static void -paint_options_brush_clicked (GtkWidget *widget, - gpointer data) +paint_options_brush_clicked (GtkWidget *widget, + GimpContext *context) { - GtkWidget *toplevel; + GtkWidget *popup; - toplevel = gtk_widget_get_toplevel (widget); - - if (GIMP_IS_DOCK (toplevel)) - gimp_dialog_factory_dialog_raise (GIMP_DOCK (toplevel)->dialog_factory, - "gimp-brush-grid", -1); + popup = gimp_container_popup_new (context->gimp->brush_factory->container, + context); + gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup), widget); } diff --git a/app/tools/paint_options.c b/app/tools/paint_options.c index 1af4b1ada4..de6f6696ec 100644 --- a/app/tools/paint_options.c +++ b/app/tools/paint_options.c @@ -28,10 +28,12 @@ #include "config/gimpconfig.h" #include "core/gimp.h" +#include "core/gimpdatafactory.h" #include "core/gimptoolinfo.h" #include "paint/gimppaintoptions.h" +#include "widgets/gimpcontainerpopup.h" #include "widgets/gimpdialogfactory.h" #include "widgets/gimpdock.h" #include "widgets/gimppropwidgets.h" @@ -65,8 +67,8 @@ static GtkWidget * gradient_options_gui (GimpGradientOptions *gradient, GType tool_type, GtkWidget *incremental_toggle); -static void paint_options_brush_clicked (GtkWidget *widget, - gpointer data); +static void paint_options_brush_clicked (GtkWidget *widget, + GimpContext *context); GtkWidget * @@ -134,7 +136,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) g_signal_connect (button, "clicked", G_CALLBACK (paint_options_brush_clicked), - NULL); + context); } /* a separator after the common paint options */ @@ -411,14 +413,12 @@ gradient_options_gui (GimpGradientOptions *gradient, } static void -paint_options_brush_clicked (GtkWidget *widget, - gpointer data) +paint_options_brush_clicked (GtkWidget *widget, + GimpContext *context) { - GtkWidget *toplevel; + GtkWidget *popup; - toplevel = gtk_widget_get_toplevel (widget); - - if (GIMP_IS_DOCK (toplevel)) - gimp_dialog_factory_dialog_raise (GIMP_DOCK (toplevel)->dialog_factory, - "gimp-brush-grid", -1); + popup = gimp_container_popup_new (context->gimp->brush_factory->container, + context); + gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup), widget); } diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am index 2e809ebec7..29a5c07b1d 100644 --- a/app/widgets/Makefile.am +++ b/app/widgets/Makefile.am @@ -47,6 +47,8 @@ libappwidgets_a_sources = \ gimpcontainermenu.h \ gimpcontainermenuimpl.c \ gimpcontainermenuimpl.h \ + gimpcontainerpopup.c \ + gimpcontainerpopup.h \ gimpcontainertreeview.c \ gimpcontainertreeview.h \ gimpcontainertreeview-dnd.c \ diff --git a/app/widgets/gimpcellrendererviewable.c b/app/widgets/gimpcellrendererviewable.c index a253118e55..93ebf2c741 100644 --- a/app/widgets/gimpcellrendererviewable.c +++ b/app/widgets/gimpcellrendererviewable.c @@ -356,13 +356,18 @@ gimp_cell_renderer_viewable_clicked (GimpCellRendererViewable *cell, event = gtk_get_current_event (); - if (event && - ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS && - ((GdkEventButton *) event)->button == 1) - gimp_preview_popup_show (gtk_get_event_widget (event), - (GdkEventButton *) event, - cell->renderer->viewable, - cell->renderer->width, - cell->renderer->height, - TRUE); + if (event) + { + + if (((GdkEventAny *) event)->type == GDK_BUTTON_PRESS && + ((GdkEventButton *) event)->button == 1) + gimp_preview_popup_show (gtk_get_event_widget (event), + (GdkEventButton *) event, + cell->renderer->viewable, + cell->renderer->width, + cell->renderer->height, + TRUE); + + gdk_event_free (event); + } } diff --git a/app/widgets/gimpcontainereditor.c b/app/widgets/gimpcontainereditor.c index 8a2a77a66d..74d6fcdba0 100644 --- a/app/widgets/gimpcontainereditor.c +++ b/app/widgets/gimpcontainereditor.c @@ -119,13 +119,12 @@ gimp_container_editor_construct (GimpContainerEditor *editor, g_return_val_if_fail (GIMP_IS_CONTAINER_EDITOR (editor), FALSE); g_return_val_if_fail (GIMP_IS_CONTAINER (container), FALSE); g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE); - g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), FALSE); - g_return_val_if_fail (menu_identifier != NULL, FALSE); - g_return_val_if_fail (preview_size > 0 && preview_size <= GIMP_PREVIEW_MAX_SIZE, FALSE); g_return_val_if_fail (min_items_x > 0 && min_items_x <= 64, FALSE); g_return_val_if_fail (min_items_y > 0 && min_items_y <= 64, FALSE); + g_return_val_if_fail (menu_factory == NULL || + GIMP_IS_MENU_FACTORY (menu_factory), FALSE); switch (view_type) { @@ -154,8 +153,9 @@ gimp_container_editor_construct (GimpContainerEditor *editor, return FALSE; } - gimp_editor_create_menu (GIMP_EDITOR (editor->view), - menu_factory, menu_identifier, editor); + if (menu_factory && menu_identifier) + gimp_editor_create_menu (GIMP_EDITOR (editor->view), + menu_factory, menu_identifier, editor); gtk_container_add (GTK_CONTAINER (editor), GTK_WIDGET (editor->view)); gtk_widget_show (GTK_WIDGET (editor->view)); diff --git a/app/widgets/gimpcontainerpopup.c b/app/widgets/gimpcontainerpopup.c new file mode 100644 index 0000000000..84c578ec30 --- /dev/null +++ b/app/widgets/gimpcontainerpopup.c @@ -0,0 +1,397 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcontainerpopup.c + * Copyright (C) 2003 Michael Natterer + * + * 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 +#include + +#include "libgimpwidgets/gimpwidgets.h" + +#include "widgets-types.h" + +#include "core/gimpcontext.h" +#include "core/gimpcontainer.h" +#include "core/gimpmarshal.h" + +#include "gimpcontainereditor.h" +#include "gimpcontainerpopup.h" +#include "gimppreview.h" + + +enum +{ + CANCEL, + CONFIRM, + LAST_SIGNAL +}; + + +static void gimp_container_popup_class_init (GimpContainerPopupClass *klass); +static void gimp_container_popup_init (GimpContainerPopup *view); + +static void gimp_container_popup_finalize (GObject *object); +static void gimp_container_popup_map (GtkWidget *widget); +static gboolean gimp_container_popup_button_press (GtkWidget *widget, + GdkEventButton *bevent); +static gboolean gimp_container_popup_key_press (GtkWidget *widget, + GdkEventKey *kevent); +static void gimp_container_popup_real_cancel (GimpContainerPopup *popup); +static void gimp_container_popup_real_confirm (GimpContainerPopup *popup); + + +static GtkWindowClass *parent_class = NULL; + +static guint popup_signals[LAST_SIGNAL]; + + +GType +gimp_container_popup_get_type (void) +{ + static GType popup_type = 0; + + if (! popup_type) + { + static const GTypeInfo popup_info = + { + sizeof (GimpContainerPopupClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gimp_container_popup_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpContainerPopup), + 0, /* n_preallocs */ + (GInstanceInitFunc) gimp_container_popup_init, + }; + + popup_type = g_type_register_static (GTK_TYPE_WINDOW, + "GimpContainerPopup", + &popup_info, 0); + } + + return popup_type; +} + +static void +gimp_container_popup_class_init (GimpContainerPopupClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkBindingSet *binding_set; + + object_class = G_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + popup_signals[CANCEL] = + g_signal_new ("cancel", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GimpContainerPopupClass, cancel), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + popup_signals[CONFIRM] = + g_signal_new ("confirm", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GimpContainerPopupClass, confirm), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_container_popup_finalize; + + widget_class->map = gimp_container_popup_map; + widget_class->button_press_event = gimp_container_popup_button_press; + widget_class->key_press_event = gimp_container_popup_key_press; + + klass->cancel = gimp_container_popup_real_cancel; + klass->confirm = gimp_container_popup_real_confirm; + + binding_set = gtk_binding_set_by_class (klass); + + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + "cancel", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, + "confirm", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, + "confirm", 0); + gtk_binding_entry_add_signal (binding_set, GDK_space, 0, + "confirm", 0); +} + +static void +gimp_container_popup_init (GimpContainerPopup *popup) +{ + popup->editor = NULL; +} + +static void +gimp_container_popup_finalize (GObject *object) +{ + GimpContainerPopup *popup; + + popup = GIMP_CONTAINER_POPUP (object); + + if (popup->context) + { + g_object_unref (popup->context); + popup->context = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_container_popup_map (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (parent_class)->map (widget); + + /* grab with owner_events == TRUE so the popup's widgets can + * receive events. we filter away events outside this toplevel + * away in button_press() + */ + if (gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK, + NULL, NULL, GDK_CURRENT_TIME) == 0) + { + if (gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME) == 0) + { + gtk_grab_add (widget); + return; + } + else + { + gdk_display_pointer_ungrab (gdk_drawable_get_display (widget->window), + GDK_CURRENT_TIME); + } + } + + /* if we could not grab, destroy the popup instead of leaving it + * around uncloseable. + */ + g_signal_emit (widget, popup_signals[CANCEL], 0); +} + +static gboolean +gimp_container_popup_button_press (GtkWidget *widget, + GdkEventButton *bevent) +{ + GimpContainerPopup *popup; + GtkWidget *event_widget; + gboolean cancel = FALSE; + + popup = GIMP_CONTAINER_POPUP (widget); + + event_widget = gtk_get_event_widget ((GdkEvent *) bevent); + + if (event_widget == widget) + { + /* the event was on the popup, which can either be really on the + * popup or outside gimp (owner_events == TRUE, see map()) + */ + if (bevent->x < 0 || + bevent->y < 0 || + bevent->x > widget->allocation.width || + bevent->y > widget->allocation.height) + { + /* the event was outsde gimp */ + + cancel = TRUE; + } + } + else if (gtk_widget_get_toplevel (event_widget) != widget) + { + /* the event was on a gimp widget, but not inside the popup */ + + cancel = TRUE; + } + + if (cancel) + g_signal_emit (widget, popup_signals[CANCEL], 0); + + return cancel; +} + +static gboolean +gimp_container_popup_key_press (GtkWidget *widget, + GdkEventKey *kevent) +{ + GtkBindingSet *binding_set; + + binding_set = + gtk_binding_set_by_class (GIMP_CONTAINER_POPUP_GET_CLASS (widget)); + + /* invoke the popup's binding entries manually, because otherwise + * the focus widget (GtkTreeView e.g.) would consume it + */ + if (gtk_binding_set_activate (binding_set, + kevent->keyval, + kevent->state, + GTK_OBJECT (widget))) + { + return TRUE; + } + + return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, kevent); +} + +static void +gimp_container_popup_real_cancel (GimpContainerPopup *popup) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (popup); + + if (gtk_grab_get_current () == widget) + gtk_grab_remove (widget); + + gtk_widget_destroy (widget); +} + +static void +gimp_container_popup_real_confirm (GimpContainerPopup *popup) +{ + GimpContextPropType prop_type; + GtkWidget *widget; + + widget = GTK_WIDGET (popup); + + prop_type = gimp_context_type_to_property (popup->container->children_type); + gimp_context_copy_property (popup->context, popup->orig_context, prop_type); + + if (gtk_grab_get_current () == widget) + gtk_grab_remove (widget); + + gtk_widget_destroy (widget); +} + +static void +gimp_container_popup_context_changed (GimpContext *context, + GimpViewable *viewable, + GimpContainerPopup *popup) +{ + GdkEvent *current_event; + gboolean confirm = FALSE; + + current_event = gtk_get_current_event (); + + if (current_event) + { + if (((GdkEventAny *) current_event)->type == GDK_BUTTON_PRESS) + confirm = TRUE; + + gdk_event_free (current_event); + } + + if (confirm) + g_signal_emit (popup, popup_signals[CONFIRM], 0); +} + +GtkWidget * +gimp_container_popup_new (GimpContainer *container, + GimpContext *context) +{ + GimpContainerPopup *popup; + GtkWidget *frame; + GtkWidget *view; + + g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL); + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + + popup = g_object_new (GIMP_TYPE_CONTAINER_POPUP, + "type", GTK_WINDOW_POPUP, + NULL); + gtk_window_set_resizable (GTK_WINDOW (popup), FALSE); + + popup->container = container; + popup->orig_context = context; + popup->context = gimp_context_new (context->gimp, "popup", context); + + g_signal_connect (popup->context, + gimp_context_type_to_signal_name (container->children_type), + G_CALLBACK (gimp_container_popup_context_changed), + popup); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (popup), frame); + gtk_widget_show (frame); + + view = g_object_new (GIMP_TYPE_CONTAINER_EDITOR, NULL); + gimp_container_editor_construct (GIMP_CONTAINER_EDITOR (view), + GIMP_VIEW_TYPE_LIST, + container, + popup->context, + GIMP_PREVIEW_SIZE_SMALL, + FALSE, /* reorderable */ + 6, 8, NULL, NULL); + gtk_container_add (GTK_CONTAINER (frame), view); + gtk_widget_show (view); + + return GTK_WIDGET (popup); +} + +void +gimp_container_popup_show (GimpContainerPopup *popup, + GtkWidget *widget) +{ + GtkRequisition requisition; + gint orig_x; + gint orig_y; + gint scr_width; + gint scr_height; + gint x; + gint y; + + g_return_if_fail (GIMP_IS_CONTAINER_POPUP (popup)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + gtk_widget_size_request (GTK_WIDGET (popup), &requisition); + gdk_window_get_origin (widget->window, &orig_x, &orig_y); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + orig_x += widget->allocation.x; + orig_y += widget->allocation.y; + } + + scr_width = gdk_screen_width (); + scr_height = gdk_screen_height (); + + x = orig_x; + y = orig_y + widget->allocation.height; + + if ((x + requisition.width) > scr_width) + x += (widget->allocation.width - requisition.width); + + if ((y + requisition.height) > scr_height) + y = orig_y - requisition.height; + + gtk_window_move (GTK_WINDOW (popup), x, y); + + gtk_widget_show (GTK_WIDGET (popup)); +} diff --git a/app/widgets/gimpcontainerpopup.h b/app/widgets/gimpcontainerpopup.h new file mode 100644 index 0000000000..0121bda881 --- /dev/null +++ b/app/widgets/gimpcontainerpopup.h @@ -0,0 +1,67 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcontainerpopup.h + * Copyright (C) 2003 Michael Natterer + * + * 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. + */ + +#ifndef __GIMP_CONTAINER_POPUP_H__ +#define __GIMP_CONTAINER_POPUP_H__ + + +#include + + +#define GIMP_TYPE_CONTAINER_POPUP (gimp_container_popup_get_type ()) +#define GIMP_CONTAINER_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CONTAINER_POPUP, GimpContainerPopup)) +#define GIMP_CONTAINER_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CONTAINER_POPUP, GimpContainerPopupClass)) +#define GIMP_IS_CONTAINER_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CONTAINER_POPUP)) +#define GIMP_IS_CONTAINER_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CONTAINER_POPUP)) +#define GIMP_CONTAINER_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CONTAINER_POPUP, GimpContainerPopupClass)) + + +typedef struct _GimpContainerPopupClass GimpContainerPopupClass; + +struct _GimpContainerPopup +{ + GtkWindow parent_instance; + + GimpContainer *container; + GimpContext *orig_context; + GimpContext *context; + + GimpContainerEditor *editor; +}; + +struct _GimpContainerPopupClass +{ + GtkWindowClass parent_instance; + + void (* cancel) (GimpContainerPopup *popup); + void (* confirm) (GimpContainerPopup *popup); +}; + + +GType gimp_container_popup_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_container_popup_new (GimpContainer *container, + GimpContext *context); +void gimp_container_popup_show (GimpContainerPopup *popup, + GtkWidget *widget); + + +#endif /* __GIMP_CONTAINER_POPUP_H__ */ diff --git a/app/widgets/gimpcontainertreeview.c b/app/widgets/gimpcontainertreeview.c index 03312ea132..00ee8c4660 100644 --- a/app/widgets/gimpcontainertreeview.c +++ b/app/widgets/gimpcontainertreeview.c @@ -552,7 +552,13 @@ gimp_container_tree_view_select_item (GimpContainerView *view, gimp_container_tree_view_selection_changed, tree_view); - gtk_tree_selection_select_path (tree_view->selection, path); +#ifdef __GNUC__ +#warning FIXME: remove this hack as soon as #108956 is fixed. +#endif + if (tree_view->main_column->editable_widget) + gtk_cell_editable_remove_widget (tree_view->main_column->editable_widget); + + gtk_tree_view_set_cursor (tree_view->view, path, NULL, FALSE); g_signal_handlers_unblock_by_func (tree_view->selection, gimp_container_tree_view_selection_changed, @@ -683,7 +689,9 @@ gimp_container_tree_view_find_click_cell (GList *cells, column_area->x + start_pos + renderer->xpad <= tree_x && column_area->x + start_pos + renderer->xpad + width - 1 >= tree_x) { +#if 0 g_print ("click on cell at %d (%d width)\n", start_pos, width); +#endif return renderer; } @@ -700,7 +708,6 @@ gimp_container_tree_view_button_press (GtkWidget *widget, GimpContainerView *container_view; GtkTreeViewColumn *column; GtkTreePath *path; - gboolean retval = FALSE; container_view = GIMP_CONTAINER_VIEW (tree_view); @@ -714,6 +721,7 @@ gimp_container_tree_view_button_press (GtkWidget *widget, GimpPreviewRenderer *renderer; GimpCellRendererToggle *toggled_cell = NULL; GimpCellRendererViewable *clicked_cell = NULL; + GtkCellRenderer *edit_cell = NULL; GdkRectangle column_area; gint tree_x; gint tree_y; @@ -749,66 +757,95 @@ gimp_container_tree_view_button_press (GtkWidget *widget, column, &column_area, tree_x, tree_y); + if (! toggled_cell && ! clicked_cell) + edit_cell = + gimp_container_tree_view_find_click_cell (tree_view->editable_cells, + column, &column_area, + tree_x, tree_y); + + g_object_ref (tree_view); + switch (bevent->button) { case 1: if (bevent->type == GDK_BUTTON_PRESS) { - if (toggled_cell || clicked_cell) - { - gchar *path_str; + /* don't select item if a toggle was clicked */ + if (! toggled_cell) + gimp_container_view_item_selected (container_view, + renderer->viewable); - path_str = gtk_tree_path_to_string (path); + /* a callback invoked by selecting the item may have + * destroyed us, so check if the container is still there + */ + if (container_view->container) + { + gchar *path_str = NULL; + + if (toggled_cell || clicked_cell) + path_str = gtk_tree_path_to_string (path); if (toggled_cell) { - /* don't select path */ gimp_cell_renderer_toggle_clicked (toggled_cell, path_str, bevent->state); } else if (clicked_cell) { - gtk_tree_selection_select_path (tree_view->selection, - path); gimp_cell_renderer_viewable_clicked (clicked_cell, path_str, bevent->state); } - g_free (path_str); - - retval = TRUE; + if (path_str) + g_free (path_str); } } else if (bevent->type == GDK_2BUTTON_PRESS) { - gimp_container_view_item_activated (container_view, - renderer->viewable); - retval = TRUE; + if (edit_cell) + { +#ifdef __GNUC__ +#warning FIXME: remove this hack as soon as #108956 is fixed. +#endif + if (column->editable_widget) + gtk_cell_editable_remove_widget (column->editable_widget); + + gtk_tree_view_set_cursor_on_cell (tree_view->view, path, + column, edit_cell, TRUE); + } + else + { + gimp_container_view_item_activated (container_view, + renderer->viewable); + } } break; case 2: - retval = TRUE; /* we want to button2-drag without selecting */ break; case 3: - gtk_tree_selection_select_path (tree_view->selection, path); - gimp_container_view_item_context (GIMP_CONTAINER_VIEW (tree_view), - renderer->viewable); - retval = TRUE; + gimp_container_view_item_selected (container_view, + renderer->viewable); + + if (container_view->container) + gimp_container_view_item_context (GIMP_CONTAINER_VIEW (tree_view), + renderer->viewable); break; default: break; } + g_object_unref (tree_view); + gtk_tree_path_free (path); g_object_unref (renderer); } - return retval; + return TRUE; } static void diff --git a/app/widgets/gimpcontainertreeview.h b/app/widgets/gimpcontainertreeview.h index 055bd0e10b..8d69cec40f 100644 --- a/app/widgets/gimpcontainertreeview.h +++ b/app/widgets/gimpcontainertreeview.h @@ -58,6 +58,7 @@ struct _GimpContainerTreeView GList *toggle_cells; GList *renderer_cells; + GList *editable_cells; gint preview_border_width; diff --git a/app/widgets/gimpcontainerview.c b/app/widgets/gimpcontainerview.c index 2d984d9164..c6c8aeeb2c 100644 --- a/app/widgets/gimpcontainerview.c +++ b/app/widgets/gimpcontainerview.c @@ -438,45 +438,54 @@ void gimp_container_view_select_item (GimpContainerView *view, GimpViewable *viewable) { - gpointer insert_data; - g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view)); g_return_if_fail (! viewable || GIMP_IS_VIEWABLE (viewable)); - insert_data = g_hash_table_lookup (view->hash_table, viewable); + if (view->hash_table) + { + gpointer insert_data; - g_signal_emit (view, view_signals[SELECT_ITEM], 0, - viewable, insert_data); + insert_data = g_hash_table_lookup (view->hash_table, viewable); + + g_signal_emit (view, view_signals[SELECT_ITEM], 0, + viewable, insert_data); + } } void gimp_container_view_activate_item (GimpContainerView *view, GimpViewable *viewable) { - gpointer insert_data; - g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view)); g_return_if_fail (GIMP_IS_VIEWABLE (viewable)); - insert_data = g_hash_table_lookup (view->hash_table, viewable); + if (view->hash_table) + { + gpointer insert_data; - g_signal_emit (view, view_signals[ACTIVATE_ITEM], 0, - viewable, insert_data); + insert_data = g_hash_table_lookup (view->hash_table, viewable); + + g_signal_emit (view, view_signals[ACTIVATE_ITEM], 0, + viewable, insert_data); + } } void gimp_container_view_context_item (GimpContainerView *view, GimpViewable *viewable) { - gpointer insert_data; - g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view)); g_return_if_fail (GIMP_IS_VIEWABLE (viewable)); - insert_data = g_hash_table_lookup (view->hash_table, viewable); + if (view->hash_table) + { + gpointer insert_data; - g_signal_emit (view, view_signals[CONTEXT_ITEM], 0, - viewable, insert_data); + insert_data = g_hash_table_lookup (view->hash_table, viewable); + + g_signal_emit (view, view_signals[CONTEXT_ITEM], 0, + viewable, insert_data); + } } void @@ -486,12 +495,31 @@ gimp_container_view_item_selected (GimpContainerView *view, g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view)); g_return_if_fail (GIMP_IS_VIEWABLE (viewable)); - if (view->container && view->context) - gimp_context_set_by_type (view->context, - view->container->children_type, - GIMP_OBJECT (viewable)); - gimp_container_view_select_item (view, viewable); + + if (view->container && view->context) + { + GimpContext *context; + + /* ref and remember the context because view->context may + * become NULL by calling gimp_context_set_by_type() + */ + context = g_object_ref (view->context); + + g_signal_handlers_block_by_func (context, + gimp_container_view_context_changed, + view); + + gimp_context_set_by_type (context, + view->container->children_type, + GIMP_OBJECT (viewable)); + + g_signal_handlers_unblock_by_func (context, + gimp_container_view_context_changed, + view); + + g_object_unref (context); + } } void diff --git a/app/widgets/gimpdatafactoryview.c b/app/widgets/gimpdatafactoryview.c index f7fcb8da19..b0fbc2a4e2 100644 --- a/app/widgets/gimpdatafactoryview.c +++ b/app/widgets/gimpdatafactoryview.c @@ -208,6 +208,9 @@ gimp_data_factory_view_construct (GimpDataFactoryView *factory_view, tree_view->name_cell->mode = GTK_CELL_RENDERER_MODE_EDITABLE; GTK_CELL_RENDERER_TEXT (tree_view->name_cell)->editable = TRUE; + tree_view->editable_cells = g_list_prepend (tree_view->editable_cells, + tree_view->name_cell); + g_signal_connect (tree_view->name_cell, "edited", G_CALLBACK (gimp_data_factory_view_tree_name_edited), factory_view); diff --git a/app/widgets/gimpitemtreeview.c b/app/widgets/gimpitemtreeview.c index eb3af01e5e..e46e137798 100644 --- a/app/widgets/gimpitemtreeview.c +++ b/app/widgets/gimpitemtreeview.c @@ -309,6 +309,9 @@ gimp_item_tree_view_constructor (GType type, tree_view->name_cell->mode = GTK_CELL_RENDERER_MODE_EDITABLE; GTK_CELL_RENDERER_TEXT (tree_view->name_cell)->editable = TRUE; + tree_view->editable_cells = g_list_prepend (tree_view->editable_cells, + tree_view->name_cell); + g_signal_connect (tree_view->name_cell, "edited", G_CALLBACK (gimp_item_tree_view_name_edited), item_view); diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index b65ae8ef91..144af9c004 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -94,6 +94,7 @@ typedef struct _GimpImageDock GimpImageDock; typedef struct _GimpDockable GimpDockable; typedef struct _GimpDockbook GimpDockbook; +typedef struct _GimpContainerPopup GimpContainerPopup; typedef struct _GimpViewableDialog GimpViewableDialog; typedef struct _GimpFontSelection GimpFontSelection;