gradient-vector.cpp revision 9b9f1cf38b528f0fc1f86654a90cd066787caf5e
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm/*
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Gradient vector selection widget
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Authors:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Lauris Kaplinski <lauris@kaplinski.com>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * bulia byak <buliabyak@users.sf.net>
1b3a8414f17dc95fc921d999ea715c99d10dd4aaAlex Valavanis * MenTaLguY <mental@rydia.net>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Jon A. Cruz <jon@joncruz.org>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Abhishek Sharma
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2001-2002 Lauris Kaplinski
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2001 Ximian, Inc.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2004 Monash University
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2004 David Turner
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2006 MenTaLguY
b1771b4ea91b15a5da4a96f93e8aa78e700fd51ajohanengelen * Copyright (C) 2010 Jon A. Cruz
5c45bb188ab729e501e48732842cb9de6a9813beAlex Valavanis *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Released under GNU GPL, read the file 'COPYING' for more information
d431763a9ec8059aa4962688de8144319969fb0fjohanengelen *
d431763a9ec8059aa4962688de8144319969fb0fjohanengelen */
d431763a9ec8059aa4962688de8144319969fb0fjohanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#ifdef HAVE_CONFIG_H
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm# include "config.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#endif
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#ifdef HAVE_STRING_H
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#endif
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "ui/widget/color-preview.h"
79d46cc367c4181803d9a7a327b163643f23e8a7cilix#include "gradient-vector.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "verbs.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <gtk/gtk.h>
5ce8d034d9fe78f969629cfe65d1a2518f173ba9cilix#include "macros.h"
0b8c1be8fec73b0ce317e9afa5ca6aa35a3b2545johanengelen#include <glibmm/i18n.h>
5ce8d034d9fe78f969629cfe65d1a2518f173ba9cilix#include "../widgets/gradient-image.h"
79d46cc367c4181803d9a7a327b163643f23e8a7cilix#include "../inkscape.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "../document-private.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "../gradient-chemistry.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "../helper/window.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
79d46cc367c4181803d9a7a327b163643f23e8a7cilix#include "xml/repr.h"
79d46cc367c4181803d9a7a327b163643f23e8a7cilix
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "../dialogs/dialog-events.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "../preferences.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "svg/css-ostringstream.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "sp-stop.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <sigc++/functors/ptr_fun.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <sigc++/adaptors/bind.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "document-undo.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmusing Inkscape::DocumentUndo;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmenum {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm VECTOR_SET,
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm LAST_SIGNAL
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm};
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gradient_vector_selector_destroy(GtkObject *object);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gvs_gradient_release(SPObject *obj, SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
79291918d036d77d586b6eba265d8d2ac0a7fee5cilixstatic void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic SPStop *get_selected_stop( GtkWidget *vb);
6d4d113f18776c07a193beeab77046b475858945johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic GtkVBoxClass *parent_class;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic guint signals[LAST_SIGNAL] = {0};
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm// TODO FIXME kill these globals!!!
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic GtkWidget *dlg = NULL;
5cf332777b4c27336d64c273ac63bce3ee27a53dAlex Valavanisstatic win_data wd;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelenstatic Glib::ustring const prefs_path = "/dialogs/gradienteditor/";
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelenGType sp_gradient_vector_selector_get_type(void)
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen{
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen static GType type = 0;
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen if (!type) {
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen static const GTypeInfo info = {
7e06f69b2d196711819d5fb5935e09cd89734bb4johanengelen sizeof(SPGradientVectorSelectorClass),
7e06f69b2d196711819d5fb5935e09cd89734bb4johanengelen NULL, /* base_init */
d37634d73670180f99a3e0ea583621373d90ec4fJohan Engelen NULL, /* base_finalize */
7e06f69b2d196711819d5fb5935e09cd89734bb4johanengelen reinterpret_cast<GClassInitFunc>(sp_gradient_vector_selector_class_init),
f84b3e8cf4811cb3ce6c33fb7341d0e836be583cjohanengelen NULL, /* class_finalize */
d90df4b5134fecb1e7248afbf601bae9d55682c6johanengelen NULL, /* class_data */
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen sizeof(SPGradientVectorSelector),
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen 0, /* n_preallocs */
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen reinterpret_cast<GInstanceInitFunc>(sp_gradient_vector_selector_init),
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen 0, /* value_table */
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen };
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
7073d105e612f7dc898c292742bee9655d2a51b2johanengelen type = g_type_register_static( GTK_TYPE_VBOX,
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm "SPGradientVectorSelector",
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm &info,
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm static_cast< GTypeFlags >(0) );
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return type;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass)
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen{
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen GtkObjectClass *object_class;
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen object_class = GTK_OBJECT_CLASS(klass);
6d4d113f18776c07a193beeab77046b475858945johanengelen
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen parent_class = static_cast<GtkVBoxClass*>(g_type_class_peek_parent(klass));
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen signals[VECTOR_SET] = g_signal_new( "vector_set",
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen G_TYPE_FROM_CLASS(object_class),
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen G_SIGNAL_RUN_LAST,
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen G_STRUCT_OFFSET(SPGradientVectorSelectorClass, vector_set),
d37634d73670180f99a3e0ea583621373d90ec4fJohan Engelen NULL, NULL,
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen g_cclosure_marshal_VOID__POINTER,
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen G_TYPE_NONE, 1,
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen G_TYPE_POINTER);
0903335a0099bd7ee779925f43a15a2216a0e863johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm object_class->destroy = sp_gradient_vector_selector_destroy;
fefed98e624e5b375661d137181340caa08440e3johanengelen}
fefed98e624e5b375661d137181340caa08440e3johanengelen
fefed98e624e5b375661d137181340caa08440e3johanengelenstatic void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs)
fefed98e624e5b375661d137181340caa08440e3johanengelen{
fefed98e624e5b375661d137181340caa08440e3johanengelen gvs->idlabel = TRUE;
fefed98e624e5b375661d137181340caa08440e3johanengelen
fefed98e624e5b375661d137181340caa08440e3johanengelen gvs->swatched = false;
fefed98e624e5b375661d137181340caa08440e3johanengelen
2015416b7a65a6c77a69ed97b746e0efbefe0578Johan B. C. Engelen gvs->doc = NULL;
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->gr = NULL;
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix new (&gvs->gradient_release_connection) sigc::connection();
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix new (&gvs->defs_release_connection) sigc::connection();
5b20351508dc029f37f23fb7add6d0b43bf47f20johanengelen new (&gvs->defs_modified_connection) sigc::connection();
0b2d8abc1011ad865fce3b883ccb2587cb15cc90Johan B. C. Engelen
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (gvs->store));
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->combo_connection = g_signal_connect (G_OBJECT (gvs->combo_box), "changed", G_CALLBACK (gr_combo_box_changed), gvs);
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new ();
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, FALSE);
1e944d29efb206f5d0b5d1069cb098e22169d548cilix gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "pixbuf", 0, NULL);
624e4bb114c588505c592e405dbad6570e5704feDiederik van Lierop gtk_cell_renderer_set_padding(renderer, 5, 0);
1e944d29efb206f5d0b5d1069cb098e22169d548cilix
624e4bb114c588505c592e405dbad6570e5704feDiederik van Lierop renderer = gtk_cell_renderer_text_new ();
5b20351508dc029f37f23fb7add6d0b43bf47f20johanengelen gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, TRUE);
42ba1b712b7b430669fc49aa9facb439181081becilix gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "text", 1, NULL);
1e944d29efb206f5d0b5d1069cb098e22169d548cilix gtk_cell_renderer_set_padding(renderer, 0, 0);
1e944d29efb206f5d0b5d1069cb098e22169d548cilix
5b20351508dc029f37f23fb7add6d0b43bf47f20johanengelen gtk_widget_show(gvs->combo_box);
0b2d8abc1011ad865fce3b883ccb2587cb15cc90Johan B. C. Engelen gtk_box_pack_start(GTK_BOX(gvs), gvs->combo_box, TRUE, TRUE, 0);
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix}
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilixstatic void sp_gradient_vector_selector_destroy(GtkObject *object)
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix{
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(object);
1e944d29efb206f5d0b5d1069cb098e22169d548cilix
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix if (gvs->gr) {
1e944d29efb206f5d0b5d1069cb098e22169d548cilix gvs->gradient_release_connection.disconnect();
1e944d29efb206f5d0b5d1069cb098e22169d548cilix gvs->gr = NULL;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix }
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
1e944d29efb206f5d0b5d1069cb098e22169d548cilix if (gvs->doc) {
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->defs_release_connection.disconnect();
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix gvs->defs_modified_connection.disconnect();
7655c8b8ffe3674dd7e7c74f450fb7194943c0deJon A. Cruz gvs->doc = NULL;
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix }
797bee69297bbdd86c5cff2e0771a71d1e2ac69dcilix
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm gvs->gradient_release_connection.~connection();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm gvs->defs_release_connection.~connection();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm gvs->defs_modified_connection.~connection();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if ((reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm (* (reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) (object);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmGtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm GtkWidget *gvs;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm g_return_val_if_fail(!gr || SP_IS_GRADIENT(gr), NULL);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm g_return_val_if_fail(!gr || (gr->document == doc), NULL);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
gvs = static_cast<GtkWidget*>(g_object_new(SP_TYPE_GRADIENT_VECTOR_SELECTOR, NULL));
if (doc) {
sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(gvs), doc, gr);
} else {
sp_gvs_rebuild_gui_full(SP_GRADIENT_VECTOR_SELECTOR(gvs));
}
return gvs;
}
void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPDocument *doc, SPGradient *gr)
{
// g_message("sp_gradient_vector_selector_set_gradient(%p, %p, %p) [%s] %d %d", gvs, doc, gr,
// (gr ? gr->getId():"N/A"),
// (gr ? gr->isSwatch() : -1),
// (gr ? gr->isSolid() : -1));
static gboolean suppress = FALSE;
g_return_if_fail(gvs != NULL);
g_return_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs));
g_return_if_fail(!gr || (doc != NULL));
g_return_if_fail(!gr || SP_IS_GRADIENT(gr));
g_return_if_fail(!gr || (gr->document == doc));
g_return_if_fail(!gr || gr->hasStops());
if (doc != gvs->doc) {
/* Disconnect signals */
if (gvs->gr) {
gvs->gradient_release_connection.disconnect();
gvs->gr = NULL;
}
if (gvs->doc) {
gvs->defs_release_connection.disconnect();
gvs->defs_modified_connection.disconnect();
gvs->doc = NULL;
}
// Connect signals
if (doc) {
gvs->defs_release_connection = doc->getDefs()->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_defs_release), gvs));
gvs->defs_modified_connection = doc->getDefs()->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gvs_defs_modified), gvs));
}
if (gr) {
gvs->gradient_release_connection = gr->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
}
gvs->doc = doc;
gvs->gr = gr;
sp_gvs_rebuild_gui_full(gvs);
if (!suppress) g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
} else if (gr != gvs->gr) {
// Harder case - keep document, rebuild list and stuff
// fixme: (Lauris)
suppress = TRUE;
sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL);
sp_gradient_vector_selector_set_gradient(gvs, doc, gr);
suppress = FALSE;
g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, gr);
}
/* The case of setting NULL -> NULL is not very interesting */
}
SPDocument *sp_gradient_vector_selector_get_document(SPGradientVectorSelector *gvs)
{
g_return_val_if_fail(gvs != NULL, NULL);
g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
return gvs->doc;
}
SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *gvs)
{
g_return_val_if_fail(gvs != NULL, NULL);
g_return_val_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs), NULL);
return gvs->gr;
}
gchar *gr_prepare_label (SPObject *obj)
{
const gchar *id = obj->defaultLabel();
if (strlen(id) > 15 && (!strncmp (id, "#linearGradient", 15) || !strncmp (id, "#radialGradient", 15)))
return g_strdup_printf ("#%s", id+15);
return g_strdup_printf ("%s", id);
}
static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs)
{
/* Clear old list, if there is any */
gtk_list_store_clear(gvs->store);
GtkTreeIter iter;
/* Pick up all gradients with vectors */
GSList *gl = NULL;
if (gvs->gr) {
const GSList *gradients = gvs->gr->document->getResourceList("gradient");
for (const GSList *curr = gradients; curr; curr = curr->next) {
SPGradient* grad = SP_GRADIENT(curr->data);
if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) {
gl = g_slist_prepend(gl, curr->data);
}
}
}
gl = g_slist_reverse(gl);
gint pos = 0;
if (!gvs->doc) {
gtk_list_store_append (gvs->store, &iter);
gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No document selected"), 2, NULL, -1);
gtk_widget_set_sensitive (gvs->combo_box, FALSE);
} else if (!gl) {
gtk_list_store_append (gvs->store, &iter);
gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradients in document"), 2, NULL, -1);
gtk_widget_set_sensitive (gvs->combo_box, FALSE);
} else if (!gvs->gr) {
gtk_list_store_append (gvs->store, &iter);
gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradient selected"), 2, NULL, -1);
gtk_widget_set_sensitive (gvs->combo_box, FALSE);
} else {
gint idx = 0;
while (gl) {
SPGradient *gr;
gr = SP_GRADIENT(gl->data);
gl = g_slist_remove(gl, gr);
/* We have to know: */
/* Gradient destroy */
/* Gradient name change */
gchar *label = gr_prepare_label(gr);
GdkPixbuf *pixb = sp_gradient_to_pixbuf (gr, 64, 18);
gtk_list_store_append (gvs->store, &iter);
gtk_list_store_set (gvs->store, &iter, 0, pixb, 1, label, 2, gr, -1);
g_free (label);
if (gr == gvs->gr) {
pos = idx;
}
idx += 1;
}
gtk_widget_set_sensitive (gvs->combo_box, TRUE);
}
/* Block signal to prevent recursive loop */
g_signal_handler_block(G_OBJECT (gvs->combo_box), gvs->combo_connection);
/* Set selected */
gtk_combo_box_set_active (GTK_COMBO_BOX(gvs->combo_box) , pos);
g_signal_handler_unblock(G_OBJECT (gvs->combo_box), gvs->combo_connection);
}
static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs)
{
GtkTreeIter iter;
if (!gtk_combo_box_get_active_iter (widget, &iter)) {
return;
}
SPGradient *gr = NULL;
gtk_tree_model_get (GTK_TREE_MODEL(gvs->store), &iter, 2, &gr, -1);
if (gr) {
SPGradient *norm = sp_gradient_ensure_vector_normalized(gr);
if (norm != gr) {
//g_print("SPGradientVectorSelector: become %s after normalization\n", norm->getId());
/* But be careful that we do not have gradient saved anywhere else */
//g_object_set_data(G_OBJECT(mi), "gradient", norm);
gtk_list_store_set (gvs->store, &iter, 2, norm, -1);
}
/* fixme: Really we would want to use _set_vector */
/* Detach old */
if (gvs->gr) {
gvs->gradient_release_connection.disconnect();
gvs->gr = NULL;
}
/* Attach new */
if (norm) {
gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs));
gvs->gr = norm;
}
g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm);
if (norm != gr) {
/* We do extra undo push here */
/* If handler has already done it, it is just NOP */
// FIXME: looks like this is never a valid undo step, consider removing this
DocumentUndo::done(norm->document, SP_VERB_CONTEXT_GRADIENT,
/* TODO: annotate */ "gradient-vector.cpp:350");
}
}
}
static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs)
{
/* Disconnect gradient */
if (gvs->gr) {
gvs->gradient_release_connection.disconnect();
gvs->gr = NULL;
}
/* Rebuild GUI */
sp_gvs_rebuild_gui_full(gvs);
}
static void sp_gvs_defs_release(SPObject */*defs*/, SPGradientVectorSelector *gvs)
{
gvs->doc = NULL;
gvs->defs_release_connection.disconnect();
gvs->defs_modified_connection.disconnect();
/* Disconnect gradient as well */
if (gvs->gr) {
gvs->gradient_release_connection.disconnect();
gvs->gr = NULL;
}
/* Rebuild GUI */
sp_gvs_rebuild_gui_full(gvs);
}
static void sp_gvs_defs_modified(SPObject */*defs*/, guint /*flags*/, SPGradientVectorSelector *gvs)
{
/* fixme: We probably have to check some flags here (Lauris) */
sp_gvs_rebuild_gui_full(gvs);
}
void SPGradientVectorSelector::setSwatched()
{
swatched = true;
sp_gvs_rebuild_gui_full(this);
}
/*##################################################################
### Vector Editing Widget
##################################################################*/
#include "../widgets/sp-color-notebook.h"
#include "../widgets/widget-sizes.h"
#include "../xml/node-event-vector.h"
#include "../svg/svg-color.h"
#define PAD 4
static GtkWidget *sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *stop);
static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient);
static gint sp_gradient_vector_dialog_delete(GtkWidget *widget, GdkEvent *event, GtkWidget *dialog);
static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data);
static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data);
static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget);
static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget);
static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object);
static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object);
static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop);
static gboolean blocked = FALSE;
static void grad_edit_dia_stop_added_or_removed(Inkscape::XML::Node */*repr*/, Inkscape::XML::Node */*child*/, Inkscape::XML::Node */*ref*/, gpointer data)
{
GtkWidget *vb = GTK_WIDGET(data);
SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
update_stop_list(vb, gradient, NULL);
}
//FIXME!!! We must also listen to attr changes on all children (i.e. stops) too,
//otherwise the dialog does not reflect undoing color or offset change. This is a major
//hassle, unless we have a "one of the descendants changed in some way" signal.
static Inkscape::XML::NodeEventVector grad_edit_dia_repr_events =
{
grad_edit_dia_stop_added_or_removed, /* child_added */
grad_edit_dia_stop_added_or_removed, /* child_removed */
NULL, /* attr_changed*/
NULL, /* content_changed */
NULL /* order_changed */
};
static void verify_grad(SPGradient *gradient)
{
int i = 0;
SPStop *stop = NULL;
/* count stops */
for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) {
if (SP_IS_STOP(ochild)) {
i++;
stop = SP_STOP(ochild);
}
}
Inkscape::XML::Document *xml_doc;
xml_doc = gradient->getRepr()->document();
if (i < 1) {
Inkscape::CSSOStringStream os;
os << "stop-color: #000000;stop-opacity:" << 1.0 << ";";
Inkscape::XML::Node *child;
child = xml_doc->createElement("svg:stop");
sp_repr_set_css_double(child, "offset", 0.0);
child->setAttribute("style", os.str().c_str());
gradient->getRepr()->addChild(child, NULL);
Inkscape::GC::release(child);
child = xml_doc->createElement("svg:stop");
sp_repr_set_css_double(child, "offset", 1.0);
child->setAttribute("style", os.str().c_str());
gradient->getRepr()->addChild(child, NULL);
Inkscape::GC::release(child);
}
if (i < 2) {
sp_repr_set_css_double(stop->getRepr(), "offset", 0.0);
Inkscape::XML::Node *child = stop->getRepr()->duplicate(gradient->getRepr()->document());
sp_repr_set_css_double(child, "offset", 1.0);
gradient->getRepr()->addChild(child, stop->getRepr());
Inkscape::GC::release(child);
}
}
static void select_stop_in_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop)
{
GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box"));
int i = 0;
for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) {
if (SP_IS_STOP(ochild)) {
if (ochild == new_stop) {
gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , i);
break;
}
i++;
}
}
}
static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop)
{
if (!SP_IS_GRADIENT(gradient)) {
return;
}
blocked = TRUE;
/* Clear old list, if there is any */
GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box"));
if (!combo_box) {
return;
}
GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box));
if (!store) {
return;
}
gtk_list_store_clear(store);
GtkTreeIter iter;
/* Populate the combobox store */
GSList *sl = NULL;
if ( gradient->hasStops() ) {
for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) {
if (SP_IS_STOP(ochild)) {
sl = g_slist_append(sl, ochild);
}
}
}
if (!sl) {
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, NULL, 1, _("No stops in gradient"), 2, NULL, -1);
gtk_widget_set_sensitive (combo_box, FALSE);
} else {
for (; sl != NULL; sl = sl->next){
if (SP_IS_STOP(sl->data)){
SPStop *stop = SP_STOP(sl->data);
Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr();
Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop)));
GdkPixbuf *pb = cpv->toPixbuf(64, 16);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, pb, 1, repr->attribute("id"), 2, stop, -1);
gtk_widget_set_sensitive (combo_box, FALSE);
}
}
gtk_widget_set_sensitive(combo_box, TRUE);
}
/* Set history */
if (new_stop == NULL) {
gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0);
} else {
select_stop_in_list(vb, gradient, new_stop);
}
blocked = FALSE;
}
// user selected existing stop from list
static void sp_grad_edit_combo_box_changed (GtkComboBox * /*widget*/, GtkWidget *tbl)
{
SPStop *stop = get_selected_stop(tbl);
if (!stop) {
return;
}
blocked = TRUE;
SPColorSelector *csel = (SPColorSelector*)g_object_get_data(G_OBJECT(tbl), "cselector");
// set its color, from the stored array
csel->base->setColorAlpha( stop->getEffectiveColor(), stop->opacity );
GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn"));
GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offslide"));
GtkAdjustment *adj = static_cast<GtkAdjustment*>(g_object_get_data(G_OBJECT(tbl), "offset"));
bool isEndStop = false;
SPStop *prev = NULL;
prev = stop->getPrevStop();
if (prev != NULL ) {
gtk_adjustment_set_lower (adj, prev->offset);
} else {
isEndStop = true;
gtk_adjustment_set_lower (adj, 0);
}
SPStop *next = NULL;
next = stop->getNextStop();
if (next != NULL ) {
gtk_adjustment_set_upper (adj, next->offset);
} else {
isEndStop = true;
gtk_adjustment_set_upper (adj, 1.0);
}
//fixme: does this work on all possible input gradients?
if (!isEndStop) {
gtk_widget_set_sensitive(offslide, TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
} else {
gtk_widget_set_sensitive(offslide, FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(offspin), FALSE);
}
gtk_adjustment_set_value(adj, stop->offset);
gtk_adjustment_changed(adj);
blocked = FALSE;
}
static SPStop *get_selected_stop( GtkWidget *vb)
{
SPStop *stop = NULL;
GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(vb), "combo_box"));
if (combo_box) {
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) {
GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box));
gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, 2, &stop, -1);
}
}
return stop;
}
static void offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb)
{
if (!blocked) {
blocked = TRUE;
SPStop *stop = get_selected_stop(vb);
if (stop) {
stop->offset = gtk_adjustment_get_value (adjustment);
sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset);
DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT,
_("Change gradient stop offset"));
}
blocked = FALSE;
}
}
guint32 sp_average_color(guint32 c1, guint32 c2, gdouble p/* = 0.5*/)
{
guint32 r = (guint32) (SP_RGBA32_R_U(c1) * p + SP_RGBA32_R_U(c2) * (1 - p));
guint32 g = (guint32) (SP_RGBA32_G_U(c1) * p + SP_RGBA32_G_U(c2) * (1 - p));
guint32 b = (guint32) (SP_RGBA32_B_U(c1) * p + SP_RGBA32_B_U(c2) * (1 - p));
guint32 a = (guint32) (SP_RGBA32_A_U(c1) * p + SP_RGBA32_A_U(c2) * (1 - p));
return SP_RGBA32_U_COMPOSE(r, g, b, a);
}
static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb)
{
SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
verify_grad(gradient);
SPStop *stop = get_selected_stop(vb);
if (!stop) {
return;
}
Inkscape::XML::Node *new_stop_repr = NULL;
SPStop *next = stop->getNextStop();
if (next == NULL) {
SPStop *prev = stop->getPrevStop();
if (prev != NULL) {
next = stop;
stop = prev;
}
}
if (next != NULL) {
new_stop_repr = stop->getRepr()->duplicate(gradient->getRepr()->document());
gradient->getRepr()->addChild(new_stop_repr, stop->getRepr());
} else {
next = stop;
new_stop_repr = stop->getPrevStop()->getRepr()->duplicate(gradient->getRepr()->document());
gradient->getRepr()->addChild(new_stop_repr, stop->getPrevStop()->getRepr());
}
SPStop *newstop = reinterpret_cast<SPStop *>(gradient->document->getObjectByRepr(new_stop_repr));
newstop->offset = (stop->offset + next->offset) * 0.5 ;
guint32 const c1 = sp_stop_get_rgba32(stop);
guint32 const c2 = sp_stop_get_rgba32(next);
guint32 cnew = sp_average_color(c1, c2);
Inkscape::CSSOStringStream os;
gchar c[64];
sp_svg_write_color(c, sizeof(c), cnew);
gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew));
os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
newstop->getRepr()->setAttribute("style", os.str().c_str());
sp_repr_set_css_double( newstop->getRepr(), "offset", (double)newstop->offset);
sp_gradient_vector_widget_load_gradient(vb, gradient);
Inkscape::GC::release(new_stop_repr);
update_stop_list(GTK_WIDGET(vb), gradient, newstop);
GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offspn"));
GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide"));
gtk_widget_set_sensitive(offslide, TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE);
DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT,
_("Add gradient stop"));
}
static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb)
{
SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient"));
SPStop *stop = get_selected_stop(vb);
if (!stop) {
return;
}
if (gradient->vector.stops.size() > 2) { // 2 is the minimum
// if we delete first or last stop, move the next/previous to the edge
if (stop->offset == 0) {
SPStop *next = stop->getNextStop();
if (next) {
next->offset = 0;
sp_repr_set_css_double(next->getRepr(), "offset", 0);
}
} else if (stop->offset == 1) {
SPStop *prev = stop->getPrevStop();
if (prev) {
prev->offset = 1;
sp_repr_set_css_double(prev->getRepr(), "offset", 1);
}
}
gradient->getRepr()->removeChild(stop->getRepr());
sp_gradient_vector_widget_load_gradient(vb, gradient);
update_stop_list(GTK_WIDGET(vb), gradient, NULL);
DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT,
_("Delete gradient stop"));
}
}
static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop)
{
GtkWidget *vb, *w, *f, *csel;
g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL);
vb = gtk_vbox_new(FALSE, PAD);
g_signal_connect(G_OBJECT(vb), "destroy", G_CALLBACK(sp_gradient_vector_widget_destroy), NULL);
w = sp_gradient_image_new(gradient);
g_object_set_data(G_OBJECT(vb), "preview", w);
gtk_widget_show(w);
gtk_box_pack_start(GTK_BOX(vb), w, TRUE, TRUE, PAD);
sp_repr_add_listener(gradient->getRepr(), &grad_edit_dia_repr_events, vb);
/* ComboBox of stops with 3 columns,
* The color preview, the label and a pointer to the SPStop
*/
GtkListStore *store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
GtkWidget *combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "pixbuf", 0, NULL);
gtk_cell_renderer_set_padding(renderer, 5, 0);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer, "text", 1, NULL);
gtk_widget_show(combo_box);
gtk_box_pack_start(GTK_BOX(vb), combo_box, FALSE, FALSE, 0);
g_object_set_data(G_OBJECT(vb), "combo_box", combo_box);
update_stop_list(GTK_WIDGET(vb), gradient, NULL);
g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(sp_grad_edit_combo_box_changed), vb);
/* Add and Remove buttons */
#if GTK_CHECK_VERSION(3,0,0)
GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
#else
GtkWidget *hb = gtk_hbox_new(FALSE, 1);
#endif
// TRANSLATORS: "Stop" means: a "phase" of a gradient
GtkWidget *b = gtk_button_new_with_label(_("Add stop"));
gtk_widget_show(b);
gtk_container_add(GTK_CONTAINER(hb), b);
gtk_widget_set_tooltip_text(b, _("Add another control stop to gradient"));
g_signal_connect(G_OBJECT(b), "clicked", G_CALLBACK(sp_grd_ed_add_stop), vb);
b = gtk_button_new_with_label(_("Delete stop"));
gtk_widget_show(b);
gtk_container_add(GTK_CONTAINER(hb), b);
gtk_widget_set_tooltip_text(b, _("Delete current control stop from gradient"));
g_signal_connect(G_OBJECT(b), "clicked", G_CALLBACK(sp_grd_ed_del_stop), vb);
gtk_widget_show(hb);
gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
/* Offset Slider and stuff */
#if GTK_CHECK_VERSION(3,0,0)
hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
#else
hb = gtk_hbox_new(FALSE, 0);
#endif
/* Label */
GtkWidget *l = gtk_label_new(_("Offset:"));
gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
gtk_box_pack_start(GTK_BOX(hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
gtk_widget_show(l);
/* Adjustment */
GtkAdjustment *Offset_adj = NULL;
Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0);
g_object_set_data(G_OBJECT(vb), "offset", Offset_adj);
SPStop *stop = get_selected_stop(vb);
if (!stop) {
return NULL;
}
gtk_adjustment_set_value(Offset_adj, stop->offset);
/* Slider */
GtkWidget *slider = gtk_hscale_new(Offset_adj);
gtk_scale_set_draw_value( GTK_SCALE(slider), FALSE );
gtk_widget_show(slider);
gtk_box_pack_start(GTK_BOX(hb),slider, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
g_object_set_data(G_OBJECT(vb), "offslide", slider);
/* Spinbutton */
GtkWidget *sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(Offset_adj), 0.01, 2);
sp_dialog_defocus_on_enter(sbtn);
gtk_widget_show(sbtn);
gtk_box_pack_start(GTK_BOX(hb),sbtn, FALSE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
g_object_set_data(G_OBJECT(vb), "offspn", sbtn);
if (stop->offset>0 && stop->offset<1) {
gtk_widget_set_sensitive(slider, TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(sbtn), TRUE);
} else {
gtk_widget_set_sensitive(slider, FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(sbtn), FALSE);
}
/* Signals */
g_signal_connect(G_OBJECT(Offset_adj), "value_changed",
G_CALLBACK(offadjustmentChanged), vb);
// g_signal_connect(G_OBJECT(slider), "changed", G_CALLBACK(offsliderChanged), vb);
gtk_widget_show(hb);
gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, PAD);
// TRANSLATORS: "Stop" means: a "phase" of a gradient
f = gtk_frame_new(_("Stop Color"));
gtk_widget_show(f);
gtk_box_pack_start(GTK_BOX(vb), f, TRUE, TRUE, PAD);
csel = static_cast<GtkWidget*>(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK));
g_object_set_data(G_OBJECT(vb), "cselector", csel);
gtk_widget_show(csel);
gtk_container_add(GTK_CONTAINER(f), csel);
g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_gradient_vector_color_dragged), vb);
g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_gradient_vector_color_changed), vb);
gtk_widget_show(vb);
sp_gradient_vector_widget_load_gradient(vb, gradient);
if (select_stop) {
select_stop_in_list(GTK_WIDGET(vb), gradient, select_stop);
}
return vb;
}
GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop)
{
GtkWidget *wid;
if (dlg == NULL) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
dlg = sp_window_new(_("Gradient editor"), TRUE);
if (x == -1000 || y == -1000) {
x = prefs->getInt(prefs_path + "x", -1000);
y = prefs->getInt(prefs_path + "y", -1000);
}
if (w ==0 || h == 0) {
w = prefs->getInt(prefs_path + "w", 0);
h = prefs->getInt(prefs_path + "h", 0);
}
if (x<0) {
x=0;
}
if (y<0) {
y=0;
}
if (x != 0 || y != 0) {
gtk_window_move(reinterpret_cast<GtkWindow *>(dlg), x, y);
} else {
gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
}
if (w && h) {
gtk_window_resize(reinterpret_cast<GtkWindow *>(dlg), w, h);
}
sp_transientize(dlg);
wd.win = dlg;
wd.stop = 0;
g_signal_connect(G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK(sp_transientize_callback), &wd);
g_signal_connect(G_OBJECT(dlg), "event", G_CALLBACK(sp_dialog_event_handler), dlg);
g_signal_connect(G_OBJECT(dlg), "destroy", G_CALLBACK(sp_gradient_vector_dialog_destroy), dlg);
g_signal_connect(G_OBJECT(dlg), "delete_event", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
g_signal_connect(G_OBJECT(INKSCAPE), "shut_down", G_CALLBACK(sp_gradient_vector_dialog_delete), dlg);
g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_hide", G_CALLBACK(sp_dialog_hide), dlg );
g_signal_connect( G_OBJECT(INKSCAPE), "dialogs_unhide", G_CALLBACK(sp_dialog_unhide), dlg );
gtk_container_set_border_width(GTK_CONTAINER(dlg), PAD);
wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop));
g_object_set_data(G_OBJECT(dlg), "gradient-vector-widget", wid);
/* Connect signals */
gtk_widget_show(wid);
gtk_container_add(GTK_CONTAINER(dlg), wid);
} else {
// FIXME: temp fix for 0.38
// Simply load_gradient into the editor does not work for multi-stop gradients,
// as the stop list and other widgets are in a wrong state and crash readily.
// Instead we just delete the window (by sending the delete signal)
// and call sp_gradient_vector_editor_new again, so it creates the window anew.
GdkEventAny event;
GtkWidget *widget = static_cast<GtkWidget *>(dlg);
event.type = GDK_DELETE;
event.window = gtk_widget_get_window (widget);
event.send_event = TRUE;
g_object_ref(G_OBJECT(event.window));
gtk_main_do_event(reinterpret_cast<GdkEvent*>(&event));
g_object_unref(G_OBJECT(event.window));
g_assert(dlg == NULL);
sp_gradient_vector_editor_new(gradient, stop);
}
return dlg;
}
static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient)
{
blocked = TRUE;
SPGradient *old;
old = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(widget), "gradient"));
if (old != gradient) {
sigc::connection *release_connection;
sigc::connection *modified_connection;
release_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(widget), "gradient_release_connection"));
modified_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(widget), "gradient_modified_connection"));
if (old) {
g_assert( release_connection != NULL );
g_assert( modified_connection != NULL );
release_connection->disconnect();
modified_connection->disconnect();
sp_signal_disconnect_by_data(old, widget);
}
if (gradient) {
if (!release_connection) {
release_connection = new sigc::connection();
}
if (!modified_connection) {
modified_connection = new sigc::connection();
}
*release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_vector_gradient_release), widget));
*modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_vector_gradient_modified), widget));
} else {
if (release_connection) {
delete release_connection;
release_connection = NULL;
}
if (modified_connection) {
delete modified_connection;
modified_connection = NULL;
}
}
g_object_set_data(G_OBJECT(widget), "gradient_release_connection", release_connection);
g_object_set_data(G_OBJECT(widget), "gradient_modified_connection", modified_connection);
}
g_object_set_data(G_OBJECT(widget), "gradient", gradient);
if (gradient) {
gtk_widget_set_sensitive(widget, TRUE);
gradient->ensureVector();
SPStop *stop = get_selected_stop(widget);
if (!stop) {
return;
}
// get the color selector
SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector"));
csel->base->setColorAlpha( stop->getEffectiveColor(), stop->opacity );
/* Fill preview */
GtkWidget *w = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(widget), "preview"));
sp_gradient_image_set_gradient(SP_GRADIENT_IMAGE(w), gradient);
update_stop_list(GTK_WIDGET(widget), gradient, NULL);
// Once the user edits a gradient, it stops being auto-collectable
if (gradient->getRepr()->attribute("inkscape:collect")) {
SPDocument *document = gradient->document;
bool saved = DocumentUndo::getUndoSensitive(document);
DocumentUndo::setUndoSensitive(document, false);
gradient->getRepr()->setAttribute("inkscape:collect", NULL);
DocumentUndo::setUndoSensitive(document, saved);
}
} else { // no gradient, disable everything
gtk_widget_set_sensitive(widget, FALSE);
}
blocked = FALSE;
}
static void sp_gradient_vector_dialog_destroy(GtkObject */*object*/, gpointer /*data*/)
{
sp_signal_disconnect_by_data(INKSCAPE, dlg);
wd.win = dlg = NULL;
wd.stop = 0;
}
static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent */*event*/, GtkWidget */*dialog*/)
{
gtk_window_get_position(GTK_WINDOW(dlg), &x, &y);
gtk_window_get_size(GTK_WINDOW(dlg), &w, &h);
if (x<0) {
x=0;
}
if (y<0) {
y=0;
}
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setInt(prefs_path + "x", x);
prefs->setInt(prefs_path + "y", y);
prefs->setInt(prefs_path + "w", w);
prefs->setInt(prefs_path + "h", h);
return FALSE; // which means, go ahead and destroy it
}
/* Widget destroy handler */
static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/)
{
SPObject *gradient = reinterpret_cast<SPObject*>(g_object_get_data(G_OBJECT(object), "gradient"));
sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection");
sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection");
if (gradient) {
g_assert( release_connection != NULL );
g_assert( modified_connection != NULL );
release_connection->disconnect();
modified_connection->disconnect();
sp_signal_disconnect_by_data(gradient, object);
}
if (gradient && gradient->getRepr()) {
sp_repr_remove_listener_by_data(gradient->getRepr(), object);
}
}
static void sp_gradient_vector_gradient_release(SPObject */*object*/, GtkWidget *widget)
{
sp_gradient_vector_widget_load_gradient(widget, NULL);
}
static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags*/, GtkWidget *widget)
{
SPGradient *gradient=SP_GRADIENT(object);
if (!blocked) {
blocked = TRUE;
sp_gradient_vector_widget_load_gradient(widget, gradient);
blocked = FALSE;
}
}
static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object)
{
SPGradient *gradient, *ngr;
if (blocked) {
return;
}
gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
if (!gradient) {
return;
}
blocked = TRUE;
ngr = sp_gradient_ensure_vector_normalized(gradient);
if (ngr != gradient) {
/* Our master gradient has changed */
sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
}
ngr->ensureVector();
SPStop *stop = get_selected_stop(GTK_WIDGET(object));
if (!stop) {
return;
}
csel->base->getColorAlpha(stop->specified_color, stop->opacity);
stop->currentColor = false;
blocked = FALSE;
}
static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object)
{
if (blocked) {
return;
}
SPGradient *gradient = static_cast<SPGradient*>(g_object_get_data(G_OBJECT(object), "gradient"));
if (!gradient) {
return;
}
blocked = TRUE;
SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient);
if (ngr != gradient) {
/* Our master gradient has changed */
sp_gradient_vector_widget_load_gradient(GTK_WIDGET(object), ngr);
}
ngr->ensureVector();
/* Set start parameters */
/* We rely on normalized vector, i.e. stops HAVE to exist */
g_return_if_fail(ngr->getFirstStop() != NULL);
SPStop *stop = get_selected_stop(GTK_WIDGET(object));
if (!stop) {
return;
}
csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(object), "cselector"));
SPColor color;
float alpha = 0;
csel->base->getColorAlpha( color, alpha );
sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset);
Inkscape::CSSOStringStream os;
os << "stop-color:" << color.toString() << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";";
stop->getRepr()->setAttribute("style", os.str().c_str());
// g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha));
//stop->getRepr()->setAttribute("style", c);
DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT,
_("Change gradient stop color"));
blocked = FALSE;
// Set the color in the selected stop after change
GtkWidget *combo_box = static_cast<GtkWidget *>(g_object_get_data(G_OBJECT(object), "combo_box"));
if (combo_box) {
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) {
GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box));
Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop)));
GdkPixbuf *pb = cp->toPixbuf(64, 16);
gtk_list_store_set (store, &iter, 0, pb, /*1, repr->attribute("id"),*/ 2, stop, -1);
}
}
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :