Commit 0089a017 authored by Michael Natterer's avatar Michael Natterer 😴

Bug 706309 - Add a “Save As” button to the “Quit GIMP” dialog

Add GimpCellRendererButton and use it to add a "Save" icon to each row
of dirty images. Click invokes the "edit-save" action, shift-click
invokes "edit-save-as". Also add a tooltip for the icon button.

Involves minor changes to GimpContainerTreeView to allow
GimpCellRendererButton to be added, and to allow external
"query-tooltip" handlers to run.
parent aa0afe0d
......@@ -37,7 +37,9 @@
#include "display/gimpdisplay.h"
#include "display/gimpdisplay-foreach.h"
#include "display/gimpdisplayshell.h"
#include "display/gimpimagewindow.h"
#include "widgets/gimpcellrendererbutton.h"
#include "widgets/gimpcontainertreestore.h"
#include "widgets/gimpcontainertreeview.h"
#include "widgets/gimpcontainerview.h"
......@@ -45,6 +47,7 @@
#include "widgets/gimphelp-ids.h"
#include "widgets/gimpmessagebox.h"
#include "widgets/gimpmessagedialog.h"
#include "widgets/gimpuimanager.h"
#include "widgets/gimpviewrenderer.h"
#include "widgets/gimpwidgets-utils.h"
......@@ -57,20 +60,22 @@ typedef struct _QuitDialog QuitDialog;
struct _QuitDialog
{
Gimp *gimp;
GimpContainer *images;
GimpContext *context;
Gimp *gimp;
GimpContainer *images;
GimpContext *context;
gboolean do_quit;
gboolean do_quit;
GtkWidget *dialog;
GtkWidget *ok_button;
GimpMessageBox *box;
GtkWidget *lost_label;
GtkWidget *hint_label;
guint accel_key;
GdkModifierType accel_mods;
GtkWidget *dialog;
GimpContainerTreeView *tree_view;
GtkTreeViewColumn *save_column;
GtkWidget *ok_button;
GimpMessageBox *box;
GtkWidget *lost_label;
GtkWidget *hint_label;
guint accel_key;
GdkModifierType accel_mods;
};
......@@ -98,7 +103,16 @@ static void quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *t
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data);
static void quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
const gchar *path,
GdkModifierType state,
QuitDialog *dialog);
static gboolean quit_close_all_dialog_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
QuitDialog *dialog);
/* public functions */
......@@ -121,6 +135,7 @@ quit_close_all_dialog_new (Gimp *gimp,
QuitDialog *dialog;
GtkWidget *view;
GimpContainerTreeView *tree_view;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkWidget *dnd_widget;
GtkAccelGroup *accel_group;
......@@ -187,15 +202,35 @@ quit_close_all_dialog_new (Gimp *gimp,
view = gimp_container_tree_view_new (dialog->images, dialog->context,
view_size, 1);
tree_view = GIMP_CONTAINER_TREE_VIEW (view);
gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (view),
-1,
rows * (view_size + 2));
dialog->tree_view = tree_view = GIMP_CONTAINER_TREE_VIEW (view);
gtk_tree_view_column_set_expand (tree_view->main_column, TRUE);
renderer = gimp_container_tree_view_get_name_cell (tree_view);
gtk_tree_view_column_set_cell_data_func (tree_view->main_column,
renderer,
quit_close_all_dialog_name_cell_func,
NULL, NULL);
gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (view),
-1,
rows * (view_size + 2));
dialog->save_column = column = gtk_tree_view_column_new ();
renderer = gimp_cell_renderer_button_new ();
g_object_set (renderer,
"icon-name", "document-save",
NULL);
gtk_tree_view_column_pack_end (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer, NULL);
gtk_tree_view_append_column (tree_view->view, column);
gimp_container_tree_view_add_toggle_cell (tree_view, renderer);
g_signal_connect (renderer, "clicked",
G_CALLBACK (quit_close_all_dialog_save_clicked),
dialog);
gtk_box_pack_start (GTK_BOX (dialog->box), view, TRUE, TRUE, 0);
gtk_widget_show (view);
......@@ -208,6 +243,10 @@ quit_close_all_dialog_new (Gimp *gimp,
(GimpDndDragViewableFunc) gimp_dnd_get_drag_data,
NULL);
g_signal_connect (tree_view->view, "query-tooltip",
G_CALLBACK (quit_close_all_dialog_query_tooltip),
dialog);
if (do_quit)
dialog->lost_label = gtk_label_new (_("If you quit GIMP now, "
"these changes will be lost."));
......@@ -436,3 +475,103 @@ quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *tree_column,
g_object_unref (renderer);
g_free (name);
}
static void
quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
const gchar *path_str,
GdkModifierType state,
QuitDialog *dialog)
{
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
GtkTreeIter iter;
if (gtk_tree_model_get_iter (dialog->tree_view->model, &iter, path))
{
GimpViewRenderer *renderer;
GimpImage *image;
GList *list;
gtk_tree_model_get (dialog->tree_view->model, &iter,
GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
-1);
image = GIMP_IMAGE (renderer->viewable);
g_object_unref (renderer);
for (list = gimp_get_display_iter (dialog->gimp);
list;
list = g_list_next (list))
{
GimpDisplay *display = list->data;
if (gimp_display_get_image (display) == image)
{
GimpDisplayShell *shell = gimp_display_get_shell (display);
GimpImageWindow *window = gimp_display_shell_get_window (shell);
if (window)
{
GimpUIManager *manager;
manager = gimp_image_window_get_ui_manager (window);
gimp_display_shell_present (shell);
if (state & GDK_SHIFT_MASK)
{
gimp_ui_manager_activate_action (manager, "file",
"file-save-as");
}
else
{
gimp_ui_manager_activate_action (manager, "file",
"file-save");
}
}
break;
}
}
}
}
static gboolean
quit_close_all_dialog_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
QuitDialog *dialog)
{
GtkTreePath *path;
gboolean show_tip = FALSE;
if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y,
keyboard_tip,
NULL, &path, NULL))
{
GtkTreeViewColumn *column = NULL;
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y,
NULL, &column, NULL, NULL);
if (column == dialog->save_column)
{
gchar *tip = g_strconcat (_("Save this image"), "\n<b>",
gimp_get_mod_string (GDK_SHIFT_MASK),
"</b> ", _("Save as"),
NULL);
gtk_tooltip_set_markup (tooltip, tip);
gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (widget), tooltip, path);
g_free (tip);
show_tip = TRUE;
}
gtk_tree_path_free (path);
}
return show_tip;
}
......@@ -43,6 +43,8 @@ libappwidgets_a_sources = \
gimpbufferview.h \
gimpcairo-wilber.c \
gimpcairo-wilber.h \
gimpcellrendererbutton.c \
gimpcellrendererbutton.h \
gimpcellrendererdashes.c \
gimpcellrendererdashes.h \
gimpcellrendererviewable.c \
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpcellrendererbutton.c
* Copyright (C) 2016 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gtk/gtk.h>
#include "widgets-types.h"
#include "core/gimpmarshal.h"
#include "gimpcellrendererbutton.h"
enum
{
CLICKED,
LAST_SIGNAL
};
static gboolean gimp_cell_renderer_button_activate (GtkCellRenderer *cell,
GdkEvent *event,
GtkWidget *widget,
const gchar *path,
GdkRectangle *background_area,
GdkRectangle *cell_area,
GtkCellRendererState flags);
G_DEFINE_TYPE (GimpCellRendererButton, gimp_cell_renderer_button,
GTK_TYPE_CELL_RENDERER_PIXBUF)
#define parent_class gimp_cell_renderer_button_parent_class
static guint button_cell_signals[LAST_SIGNAL] = { 0 };
static void
gimp_cell_renderer_button_class_init (GimpCellRendererButtonClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
/**
* GimpCellRendererButton::clicked:
* @cell:
* @path:
* @state:
*
* Called on a button cell when it is clicked.
**/
button_cell_signals[CLICKED] =
g_signal_new ("clicked",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GimpCellRendererButtonClass, clicked),
NULL, NULL,
gimp_marshal_VOID__STRING_FLAGS,
G_TYPE_NONE, 2,
G_TYPE_STRING,
GDK_TYPE_MODIFIER_TYPE);
cell_class->activate = gimp_cell_renderer_button_activate;
klass->clicked = NULL;
}
static void
gimp_cell_renderer_button_init (GimpCellRendererButton *cell_button)
{
g_object_set (cell_button,
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
"xpad", 2,
"ypad", 2,
"follow-state", TRUE,
"stock-size", GTK_ICON_SIZE_BUTTON,
NULL);
}
static gboolean
gimp_cell_renderer_button_activate (GtkCellRenderer *cell,
GdkEvent *event,
GtkWidget *widget,
const gchar *path,
GdkRectangle *background_area,
GdkRectangle *cell_area,
GtkCellRendererState flags)
{
GimpCellRendererButton *cell_button = GIMP_CELL_RENDERER_BUTTON (cell);
GdkModifierType state = 0;
if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
state = ((GdkEventButton *) event)->state;
if (! event ||
(((GdkEventAny *) event)->type == GDK_BUTTON_PRESS &&
((GdkEventButton *) event)->button == 1))
{
gimp_cell_renderer_button_clicked (cell_button, path, state);
return TRUE;
}
return FALSE;
}
/* public functions */
GtkCellRenderer *
gimp_cell_renderer_button_new (void)
{
return g_object_new (GIMP_TYPE_CELL_RENDERER_BUTTON, NULL);
}
void
gimp_cell_renderer_button_clicked (GimpCellRendererButton *cell,
const gchar *path,
GdkModifierType state)
{
g_return_if_fail (GIMP_IS_CELL_RENDERER_BUTTON (cell));
g_return_if_fail (path != NULL);
g_signal_emit (cell, button_cell_signals[CLICKED], 0, path, state);
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpcellrendererbutton.h
* Copyright (C) 2016 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_CELL_RENDERER_BUTTON_H__
#define __GIMP_CELL_RENDERER_BUTTON_H__
#define GIMP_TYPE_CELL_RENDERER_BUTTON (gimp_cell_renderer_button_get_type ())
#define GIMP_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButton))
#define GIMP_CELL_RENDERER_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButtonClass))
#define GIMP_IS_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON))
#define GIMP_IS_CELL_RENDERER_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CELL_RENDERER_BUTTON))
#define GIMP_CELL_RENDERER_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButtonClass))
typedef struct _GimpCellRendererButtonClass GimpCellRendererButtonClass;
struct _GimpCellRendererButton
{
GtkCellRendererPixbuf parent_instance;
};
struct _GimpCellRendererButtonClass
{
GtkCellRendererPixbufClass parent_class;
void (* clicked) (GimpCellRendererButton *cell,
const gchar *path,
GdkModifierType state);
};
GType gimp_cell_renderer_button_get_type (void) G_GNUC_CONST;
GtkCellRenderer * gimp_cell_renderer_button_new (void);
void gimp_cell_renderer_button_clicked (GimpCellRendererButton *cell,
const gchar *path,
GdkModifierType state);
#endif /* __GIMP_CELL_RENDERER_BUTTON_H__ */
......@@ -35,6 +35,7 @@
#include "core/gimpmarshal.h"
#include "core/gimpviewable.h"
#include "gimpcellrendererbutton.h"
#include "gimpcellrendererviewable.h"
#include "gimpcontainertreestore.h"
#include "gimpcontainertreeview.h"
......@@ -321,9 +322,12 @@ gimp_container_tree_view_constructed (GObject *object)
G_CALLBACK (gimp_container_tree_view_drag_data_received),
tree_view);
g_signal_connect (tree_view->view, "query-tooltip",
G_CALLBACK (gimp_container_tree_view_tooltip),
tree_view);
/* connect_after so external code can connect to "query-tooltip" too
* and override the default tip
*/
g_signal_connect_after (tree_view->view, "query-tooltip",
G_CALLBACK (gimp_container_tree_view_tooltip),
tree_view);
}
static void
......@@ -520,7 +524,8 @@ gimp_container_tree_view_add_toggle_cell (GimpContainerTreeView *tree_view,
GtkCellRenderer *cell)
{
g_return_if_fail (GIMP_IS_CONTAINER_TREE_VIEW (tree_view));
g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell) ||
GIMP_IS_CELL_RENDERER_BUTTON (cell));
tree_view->priv->toggle_cells = g_list_prepend (tree_view->priv->toggle_cells,
cell);
......@@ -1043,7 +1048,7 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
&path, &column, NULL, NULL))
{
GimpViewRenderer *renderer;
GimpCellRendererToggle *toggled_cell = NULL;
GtkCellRenderer *toggled_cell = NULL;
GimpCellRendererViewable *clicked_cell = NULL;
GtkCellRenderer *edit_cell = NULL;
GdkRectangle column_area;
......@@ -1098,7 +1103,7 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
g_list_free (cells);
}
toggled_cell = (GimpCellRendererToggle *)
toggled_cell =
gimp_container_tree_view_find_click_cell (widget,
tree_view->priv->toggle_cells,
column, &column_area,
......@@ -1181,9 +1186,18 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
if (toggled_cell)
{
gimp_cell_renderer_toggle_clicked (toggled_cell,
path_str,
bevent->state);
if (GIMP_IS_CELL_RENDERER_TOGGLE (toggled_cell))
{
gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (toggled_cell),
path_str,
bevent->state);
}
else if (GIMP_IS_CELL_RENDERER_BUTTON (toggled_cell))
{
gimp_cell_renderer_button_clicked (GIMP_CELL_RENDERER_BUTTON (toggled_cell),
path_str,
bevent->state);
}
}
else if (clicked_cell)
{
......
......@@ -240,6 +240,7 @@ typedef struct _GimpViewRendererVectors GimpViewRendererVectors;
/* cell renderers */
typedef struct _GimpCellRendererButton GimpCellRendererButton;
typedef struct _GimpCellRendererDashes GimpCellRendererDashes;
typedef struct _GimpCellRendererViewable GimpCellRendererViewable;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment