sp-color-icc-selector.cpp revision 827fbd361779d76f0dff3dff3962b8486426ea01
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gradient-vector.h"
#include <math.h>
#include <gtk/gtk.h>
#include <glibmm/i18n.h>
#include <map>
#include <set>
#include <vector>
#include "../dialogs/dialog-events.h"
#include "sp-color-icc-selector.h"
#include "sp-color-scales.h"
#include "ui/widget/color-slider.h"
#include "svg/svg-icc-color.h"
#include "colorspace.h"
#include "document.h"
#include "inkscape.h"
#include "profile-manager.h"
#define noDEBUG_LCMS
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
#include "color-profile.h"
#include "cms-system.h"
#include "color-profile-cms-fns.h"
#ifdef DEBUG_LCMS
#include "preferences.h"
#endif // DEBUG_LCMS
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
#ifdef DEBUG_LCMS
extern guint update_in_progress;
#define DEBUG_MESSAGE(key, ...) \
{\
Inkscape::Preferences *prefs = Inkscape::Preferences::get();\
bool dump = prefs->getBool("/options/scislac/" #key);\
bool dumpD = prefs->getBool("/options/scislac/" #key "D");\
bool dumpD2 = prefs->getBool("/options/scislac/" #key "D2");\
dumpD &&= ( (update_in_progress == 0) || dumpD2 );\
if ( dump )\
{\
g_message( __VA_ARGS__ );\
\
}\
if ( dumpD )\
{\
GtkWidget *dialog = gtk_message_dialog_new(NULL,\
GTK_DIALOG_DESTROY_WITH_PARENT, \
GTK_MESSAGE_INFO, \
GTK_BUTTONS_OK, \
__VA_ARGS__ \
);\
g_signal_connect_swapped(dialog, "response",\
G_CALLBACK(gtk_widget_destroy), \
dialog); \
gtk_widget_show_all( dialog );\
}\
}
#endif // DEBUG_LCMS
G_BEGIN_DECLS
static void sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass);
static void sp_color_icc_selector_init (SPColorICCSelector *cs);
static void sp_color_icc_selector_dispose(GObject *object);
static void sp_color_icc_selector_show_all (GtkWidget *widget);
static void sp_color_icc_selector_hide(GtkWidget *widget);
G_END_DECLS
/**
* Class containing the parts for a single color component's UI presence.
*/
class ComponentUI
{
public:
ComponentUI() :
_component(),
_adj(0),
_slider(0),
_btn(0),
_label(0),
_map(0)
{
}
ComponentUI(colorspace::Component const &component) :
_component(component),
_adj(0),
_slider(0),
_btn(0),
_label(0),
_map(0)
{
}
colorspace::Component _component;
GtkAdjustment *_adj; // Component adjustment
GtkWidget *_slider;
GtkWidget *_btn; // spinbutton
GtkWidget *_label; // Label
guchar *_map;
};
/**
* Class that implements the internals of the selector.
*/
class ColorICCSelectorImpl
{
public:
ColorICCSelectorImpl( ColorICCSelector *owner);
~ColorICCSelectorImpl();
static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs );
static void _sliderGrabbed( SPColorSlider *slider, SPColorICCSelector *cs );
static void _sliderReleased( SPColorSlider *slider, SPColorICCSelector *cs );
static void _sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs );
static void _profileSelected( GtkWidget* src, gpointer data );
static void _fixupHit( GtkWidget* src, gpointer data );
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void _setProfile( SVGICCColor* profile );
void _switchToProfile( gchar const* name );
#endif
void _updateSliders( gint ignore );
void _profilesChanged( std::string const & name );
ColorICCSelector *_owner;
gboolean _updating : 1;
gboolean _dragging : 1;
guint32 _fixupNeeded;
GtkWidget* _fixupBtn;
GtkWidget* _profileSel;
std::vector<ComponentUI> _compUI;
GtkAdjustment* _adj; // Channel adjustment
GtkWidget* _slider;
GtkWidget* _sbtn; // Spinbutton
GtkWidget* _label; // Label
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
std::string _profileName;
Inkscape::ColorProfile* _prof;
guint _profChannelCount;
gulong _profChangedID;
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
};
static SPColorSelectorClass *parent_class;
#define XPAD 4
#define YPAD 1
namespace
{
size_t maxColorspaceComponentCount = 0;
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
/**
* Internal variable to track all known colorspaces.
*/
std::set<cmsUInt32Number> knownColorspaces;
#endif
/**
* Simple helper to allow bitwise or on GtkAttachOptions.
*/
GtkAttachOptions operator|(GtkAttachOptions lhs, GtkAttachOptions rhs)
{
return static_cast<GtkAttachOptions>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
/**
* Helper function to handle GTK2/GTK3 attachment #ifdef code.
*/
void attachToGridOrTable(GtkWidget *parent,
GtkWidget *child,
guint left,
guint top,
guint width,
guint height,
bool hexpand = false,
bool centered = false,
guint xpadding = XPAD,
guint ypadding = YPAD)
{
#if GTK_CHECK_VERSION(3,0,0)
gtk_widget_set_margin_left( child, xpadding );
gtk_widget_set_margin_right( child, xpadding );
gtk_widget_set_margin_top( child, ypadding );
gtk_widget_set_margin_bottom( child, ypadding );
if (hexpand) {
gtk_widget_set_hexpand(child, TRUE);
}
if (centered) {
gtk_widget_set_halign( child, GTK_ALIGN_CENTER );
gtk_widget_set_valign( child, GTK_ALIGN_CENTER );
}
gtk_grid_attach( GTK_GRID(parent), child, left, top, width, height );
#else
GtkAttachOptions xoptions = centered ? static_cast<GtkAttachOptions>(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL;
GtkAttachOptions yoptions = centered ? static_cast<GtkAttachOptions>(0) : GTK_FILL;
gtk_table_attach( GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, ypadding );
#endif
}
} // namespace
GType sp_color_icc_selector_get_type(void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof (SPColorICCSelectorClass),
NULL, // base_init
NULL, // base_finalize
(GClassInitFunc) sp_color_icc_selector_class_init,
NULL, // class_finalize
NULL, // class_data
sizeof (SPColorICCSelector),
0, // n_preallocs
(GInstanceInitFunc) sp_color_icc_selector_init,
0, // value_table
};
type = g_type_register_static (SP_TYPE_COLOR_SELECTOR,
"SPColorICCSelector",
&info,
static_cast< GTypeFlags > (0) );
}
return type;
}
static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass)
{
static const gchar* nameset[] = {N_("CMS"), 0};
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass);
parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass));
selector_class->name = nameset;
selector_class->submode_count = 1;
object_class->dispose = sp_color_icc_selector_dispose;
widget_class->show_all = sp_color_icc_selector_show_all;
widget_class->hide = sp_color_icc_selector_hide;
}
ColorICCSelector::ColorICCSelector( SPColorSelector* csel )
: ColorSelector( csel ),
_impl(NULL)
{
}
ColorICCSelector::~ColorICCSelector()
{
if (_impl)
{
delete _impl;
_impl = 0;
}
}
void sp_color_icc_selector_init(SPColorICCSelector *cs)
{
SP_COLOR_SELECTOR(cs)->base = new ColorICCSelector( SP_COLOR_SELECTOR(cs) );
if ( SP_COLOR_SELECTOR(cs)->base )
{
SP_COLOR_SELECTOR(cs)->base->init();
}
}
/*
icSigRgbData
icSigCmykData
icSigCmyData
*/
#define SPACE_ID_RGB 0
#define SPACE_ID_CMY 1
#define SPACE_ID_CMYK 2
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
static cmsUInt16Number* getScratch() {
// bytes per pixel * input channels * width
static cmsUInt16Number* scritch = static_cast<cmsUInt16Number*>(g_new(cmsUInt16Number, 4 * 1024));
return scritch;
}
colorspace::Component::Component() :
name(),
tip(),
scale(1)
{
}
colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) :
name(name),
tip(tip),
scale(scale)
{
}
std::vector<colorspace::Component> colorspace::getColorSpaceInfo( uint32_t space )
{
static std::map<cmsUInt32Number, std::vector<Component> > sets;
if (sets.empty())
{
sets[cmsSigXYZData].push_back(Component("_X", "X", 2)); // TYPE_XYZ_16
sets[cmsSigXYZData].push_back(Component("_Y", "Y", 1));
sets[cmsSigXYZData].push_back(Component("_Z", "Z", 2));
sets[cmsSigLabData].push_back(Component("_L", "L", 100)); // TYPE_Lab_16
sets[cmsSigLabData].push_back(Component("_a", "a", 256));
sets[cmsSigLabData].push_back(Component("_b", "b", 256));
//cmsSigLuvData
sets[cmsSigYCbCrData].push_back(Component("_Y", "Y", 1)); // TYPE_YCbCr_16
sets[cmsSigYCbCrData].push_back(Component("C_b", "Cb", 1));
sets[cmsSigYCbCrData].push_back(Component("C_r", "Cr", 1));
sets[cmsSigYxyData].push_back(Component("_Y", "Y", 1)); // TYPE_Yxy_16
sets[cmsSigYxyData].push_back(Component("_x", "x", 1));
sets[cmsSigYxyData].push_back(Component("y", "y", 1));
sets[cmsSigRgbData].push_back(Component(_("_R:"), _("Red"), 1)); // TYPE_RGB_16
sets[cmsSigRgbData].push_back(Component(_("_G:"), _("Green"), 1));
sets[cmsSigRgbData].push_back(Component(_("_B:"), _("Blue"), 1));
sets[cmsSigGrayData].push_back(Component(_("G:"), _("Gray"), 1)); // TYPE_GRAY_16
sets[cmsSigHsvData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HSV_16
sets[cmsSigHsvData].push_back(Component(_("_S:"), _("Saturation"), 1));
sets[cmsSigHsvData].push_back(Component("_V:", "Value", 1));
sets[cmsSigHlsData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HLS_16
sets[cmsSigHlsData].push_back(Component(_("_L:"), _("Lightness"), 1));
sets[cmsSigHlsData].push_back(Component(_("_S:"), _("Saturation"), 1));
sets[cmsSigCmykData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMYK_16
sets[cmsSigCmykData].push_back(Component(_("_M:"), _("Magenta"), 1));
sets[cmsSigCmykData].push_back(Component(_("_Y:"), _("Yellow"), 1));
sets[cmsSigCmykData].push_back(Component(_("_K:"), _("Black"), 1));
sets[cmsSigCmyData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMY_16
sets[cmsSigCmyData].push_back(Component(_("_M:"), _("Magenta"), 1));
sets[cmsSigCmyData].push_back(Component(_("_Y:"), _("Yellow"), 1));
for (std::map<cmsUInt32Number, std::vector<Component> >::iterator it = sets.begin(); it != sets.end(); ++it)
{
knownColorspaces.insert(it->first);
maxColorspaceComponentCount = std::max(maxColorspaceComponentCount, it->second.size());
}
}
std::vector<Component> target;
if (sets.find(space) != sets.end())
{
target = sets[space];
}
return target;
}
std::vector<colorspace::Component> colorspace::getColorSpaceInfo( Inkscape::ColorProfile *prof )
{
return getColorSpaceInfo( asICColorSpaceSig(prof->getColorSpace()) );
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner) :
_owner(owner),
_updating( FALSE ),
_dragging( FALSE ),
_fixupNeeded(0),
_fixupBtn(0),
_profileSel(0),
_compUI(),
_adj(0),
_slider(0),
_sbtn(0),
_label(0)
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
,
_profileName(),
_prof(0),
_profChannelCount(0),
_profChangedID(0)
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
{
}
ColorICCSelectorImpl::~ColorICCSelectorImpl()
{
_adj = 0;
_sbtn = 0;
_label = 0;
}
void ColorICCSelector::init()
{
if (_impl) delete(_impl);
_impl = new ColorICCSelectorImpl(this);
gint row = 0;
_impl->_updating = FALSE;
_impl->_dragging = FALSE;
#if GTK_CHECK_VERSION(3,0,0)
GtkWidget *t = gtk_grid_new();
#else
GtkWidget *t = gtk_table_new(5, 3, FALSE);
#endif
gtk_widget_show (t);
gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4);
_impl->_compUI.clear();
// Create components
row = 0;
_impl->_fixupBtn = gtk_button_new_with_label(_("Fix"));
g_signal_connect( G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), (gpointer)_impl );
gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE );
gtk_widget_set_tooltip_text( _impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.") );
//gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 );
gtk_widget_show( _impl->_fixupBtn );
attachToGridOrTable(t, _impl->_fixupBtn, 0, row, 1, 1);
// Combobox and store with 2 columns : label (0) and full name (1)
GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
_impl->_profileSel = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, "text", 0, NULL);
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, _("<none>"), 1, _("<none>"), -1);
gtk_widget_show( _impl->_profileSel );
gtk_combo_box_set_active( GTK_COMBO_BOX(_impl->_profileSel), 0 );
attachToGridOrTable(t, _impl->_profileSel, 1, row, 1, 1);
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
_impl->_profChangedID = g_signal_connect( G_OBJECT(_impl->_profileSel), "changed", G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl );
#else
gtk_widget_set_sensitive( _impl->_profileSel, false );
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
row++;
// populate the data for colorspaces and channels:
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo( cmsSigRgbData );
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
for ( size_t i = 0; i < maxColorspaceComponentCount; i++ ) {
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
if (i < things.size()) {
_impl->_compUI.push_back(ComponentUI(things[i]));
} else {
_impl->_compUI.push_back(ComponentUI());
}
std::string labelStr = (i < things.size()) ? things[i].name.c_str() : "";
#else
_impl->_compUI.push_back(ComponentUI());
std::string labelStr = ".";
#endif
_impl->_compUI[i]._label = gtk_label_new_with_mnemonic( labelStr.c_str() );
gtk_misc_set_alignment( GTK_MISC (_impl->_compUI[i]._label), 1.0, 0.5 );
gtk_widget_show( _impl->_compUI[i]._label );
attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1);
// Adjustment
guint scaleValue = _impl->_compUI[i]._component.scale;
gdouble step = static_cast<gdouble>(scaleValue) / 100.0;
gdouble page = static_cast<gdouble>(scaleValue) / 10.0;
gint digits = (step > 0.9) ? 0 : 2;
_impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) );
// Slider
_impl->_compUI[i]._slider = sp_color_slider_new( _impl->_compUI[i]._adj );
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" );
#else
gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, "." );
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
gtk_widget_show( _impl->_compUI[i]._slider );
attachToGridOrTable(t, _impl->_compUI[i]._slider, 1, row, 1, 1, true);
_impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits );
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" );
#else
gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, "." );
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
sp_dialog_defocus_on_enter( _impl->_compUI[i]._btn );
gtk_label_set_mnemonic_widget( GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn );
gtk_widget_show( _impl->_compUI[i]._btn );
attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true);
_impl->_compUI[i]._map = g_new( guchar, 4 * 1024 );
memset( _impl->_compUI[i]._map, 0x0ff, 1024 * 4 );
// Signals
g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel );
g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "grabbed", G_CALLBACK( ColorICCSelectorImpl::_sliderGrabbed ), _csel );
g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "released", G_CALLBACK( ColorICCSelectorImpl::_sliderReleased ), _csel );
g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "changed", G_CALLBACK( ColorICCSelectorImpl::_sliderChanged ), _csel );
row++;
}
// Label
_impl->_label = gtk_label_new_with_mnemonic(_("_A:"));
gtk_misc_set_alignment(GTK_MISC(_impl->_label), 1.0, 0.5);
gtk_widget_show(_impl->_label);
attachToGridOrTable(t, _impl->_label, 0, row, 1, 1);
// Adjustment
_impl->_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0));
// Slider
_impl->_slider = sp_color_slider_new(_impl->_adj);
gtk_widget_set_tooltip_text(_impl->_slider, _("Alpha (opacity)"));
gtk_widget_show(_impl->_slider);
attachToGridOrTable(t, _impl->_slider, 1, row, 1, 1, true);
sp_color_slider_set_colors( SP_COLOR_SLIDER( _impl->_slider ),
SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ),
SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ),
SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) );
// Spinbutton
_impl->_sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(_impl->_adj), 1.0, 0);
gtk_widget_set_tooltip_text(_impl->_sbtn, _("Alpha (opacity)"));
sp_dialog_defocus_on_enter(_impl->_sbtn);
gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_label), _impl->_sbtn);
gtk_widget_show(_impl->_sbtn);
attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true);
// Signals
g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel);
g_signal_connect(G_OBJECT(_impl->_slider), "grabbed", G_CALLBACK(ColorICCSelectorImpl::_sliderGrabbed), _csel);
g_signal_connect(G_OBJECT(_impl->_slider), "released", G_CALLBACK(ColorICCSelectorImpl::_sliderReleased), _csel);
g_signal_connect(G_OBJECT(_impl->_slider), "changed", G_CALLBACK(ColorICCSelectorImpl::_sliderChanged), _csel);
}
static void sp_color_icc_selector_dispose(GObject *object)
{
if ((G_OBJECT_CLASS(parent_class))->dispose) {
(* (G_OBJECT_CLASS(parent_class))->dispose)(object);
}
}
static void
sp_color_icc_selector_show_all (GtkWidget *widget)
{
gtk_widget_show (widget);
}
static void sp_color_icc_selector_hide(GtkWidget *widget)
{
gtk_widget_hide(widget);
}
GtkWidget *
sp_color_icc_selector_new (void)
{
SPColorICCSelector *csel;
csel = static_cast<SPColorICCSelector*>(g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL));
return GTK_WIDGET (csel);
}
void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data )
{
ColorICCSelectorImpl* self = reinterpret_cast<ColorICCSelectorImpl*>(data);
gtk_widget_set_sensitive( self->_fixupBtn, FALSE );
self->_adjustmentChanged( self->_compUI[0]._adj, SP_COLOR_ICC_SELECTOR(self->_owner->_csel) );
}
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data )
{
ColorICCSelectorImpl* self = reinterpret_cast<ColorICCSelectorImpl*>(data);
GtkTreeIter iter;
if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_profileSel), &iter)) {
GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(self->_profileSel));
gchar* name = 0;
gtk_tree_model_get(store, &iter, 1, &name, -1);
self->_switchToProfile( name );
gtk_widget_set_tooltip_text(self->_profileSel, name );
if ( name ) {
g_free( name );
}
}
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void ColorICCSelectorImpl::_switchToProfile( gchar const* name )
{
bool dirty = false;
SPColor tmp( _owner->_color );
if ( name ) {
if ( tmp.icc && tmp.icc->colorProfile == name ) {
#ifdef DEBUG_LCMS
g_message("Already at name [%s]", name );
#endif // DEBUG_LCMS
} else {
#ifdef DEBUG_LCMS
g_message("Need to switch to profile [%s]", name );
#endif // DEBUG_LCMS
if ( tmp.icc ) {
tmp.icc->colors.clear();
} else {
tmp.icc = new SVGICCColor();
}
tmp.icc->colorProfile = name;
Inkscape::ColorProfile* newProf = SP_ACTIVE_DOCUMENT->profileManager->find(name);
if ( newProf ) {
cmsHTRANSFORM trans = newProf->getTransfFromSRGB8();
if ( trans ) {
guint32 val = _owner->_color.toRGBA32(0);
guchar pre[4] = {
static_cast<guchar>(SP_RGBA32_R_U(val)),
static_cast<guchar>(SP_RGBA32_G_U(val)),
static_cast<guchar>(SP_RGBA32_B_U(val)),
255};
#ifdef DEBUG_LCMS
g_message("Shoving in [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]);
#endif // DEBUG_LCMS
cmsUInt16Number post[4] = {0,0,0,0};
cmsDoTransform( trans, pre, post, 1 );
#ifdef DEBUG_LCMS
g_message("got on out [%04x] [%04x] [%04x] [%04x]", post[0], post[1], post[2], post[3]);
#endif // DEBUG_LCMS
#if HAVE_LIBLCMS1
guint count = _cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) );
#elif HAVE_LIBLCMS2
guint count = cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) );
#endif
std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace()));
for ( guint i = 0; i < count; i++ ) {
gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1);
#ifdef DEBUG_LCMS
g_message(" scaled %d by %d to be %f", i, ((i < things.size()) ? things[i].scale : 1), val);
#endif // DEBUG_LCMS
tmp.icc->colors.push_back(val);
}
cmsHTRANSFORM retrans = newProf->getTransfToSRGB8();
if ( retrans ) {
cmsDoTransform( retrans, post, pre, 1 );
#ifdef DEBUG_LCMS
g_message(" back out [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]);
#endif // DEBUG_LCMS
tmp.set(SP_RGBA32_U_COMPOSE(pre[0], pre[1], pre[2], 0xff));
}
}
}
dirty = true;
}
} else {
#ifdef DEBUG_LCMS
g_message("NUKE THE ICC");
#endif // DEBUG_LCMS
if ( tmp.icc ) {
delete tmp.icc;
tmp.icc = 0;
dirty = true;
_fixupHit( 0, this );
} else {
#ifdef DEBUG_LCMS
g_message("No icc to nuke");
#endif // DEBUG_LCMS
}
}
if ( dirty ) {
#ifdef DEBUG_LCMS
g_message("+----------------");
g_message("+ new color is [%s]", tmp.toString().c_str());
#endif // DEBUG_LCMS
_setProfile( tmp.icc );
//_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) );
_owner->setColorAlpha( tmp, _owner->_alpha, true );
#ifdef DEBUG_LCMS
g_message("+_________________");
#endif // DEBUG_LCMS
}
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void ColorICCSelectorImpl::_profilesChanged( std::string const & name )
{
GtkComboBox* combo = GTK_COMBO_BOX(_profileSel);
g_signal_handler_block( G_OBJECT(_profileSel), _profChangedID );
GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo));
gtk_list_store_clear(store);
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set(store, &iter, 0, _("<none>"), 1, _("<none>"), -1);
gtk_combo_box_set_active( combo, 0 );
int index = 1;
const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
while ( current ) {
SPObject* obj = SP_OBJECT(current->data);
Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj);
gtk_list_store_append (store, &iter);
gtk_list_store_set(store, &iter, 0, gr_ellipsize_text(prof->name, 25).c_str(), 1, prof->name, -1);
if ( name == prof->name ) {
gtk_combo_box_set_active( combo, index );
gtk_widget_set_tooltip_text(_profileSel, prof->name );
}
index++;
current = g_slist_next(current);
}
g_signal_handler_unblock( G_OBJECT(_profileSel), _profChangedID );
}
#else
void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ )
{
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
// Helpers for setting color value
void ColorICCSelector::_colorChanged()
{
_impl->_updating = TRUE;
//sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color );
#ifdef DEBUG_LCMS
g_message( "/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this,
_color.toRGBA32(_alpha), ( (_color.icc) ? _color.icc->colorProfile.c_str(): "<null>" )
);
#endif // DEBUG_LCMS
#ifdef DEBUG_LCMS
g_message("FLIPPIES!!!! %p '%s'", _color.icc, (_color.icc ? _color.icc->colorProfile.c_str():"<null>"));
#endif // DEBUG_LCMS
_impl->_profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") );
ColorScales::setScaled( _impl->_adj, _alpha );
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
_impl->_setProfile( _color.icc );
_impl->_fixupNeeded = 0;
gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE );
if (_impl->_prof) {
if (_impl->_prof->getTransfToSRGB8() ) {
cmsUInt16Number tmp[4];
for ( guint i = 0; i < _impl->_profChannelCount; i++ ) {
gdouble val = 0.0;
if ( _color.icc->colors.size() > i ) {
if ( _impl->_compUI[i]._component.scale == 256 ) {
val = (_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_impl->_compUI[i]._component.scale);
} else {
val = _color.icc->colors[i] / static_cast<gdouble>(_impl->_compUI[i]._component.scale);
}
}
tmp[i] = val * 0x0ffff;
}
guchar post[4] = {0,0,0,0};
cmsHTRANSFORM trans = _impl->_prof->getTransfToSRGB8();
if ( trans ) {
cmsDoTransform( trans, tmp, post, 1 );
guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 );
if ( other != _color.toRGBA32(255) ) {
_impl->_fixupNeeded = other;
gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE );
#ifdef DEBUG_LCMS
g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 );
#endif // DEBUG_LCMS
}
}
}
}
#else
//(void)color;
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
_impl->_updateSliders( -1 );
_impl->_updating = FALSE;
#ifdef DEBUG_LCMS
g_message( "\\_________ %p::_colorChanged()", this );
#endif // DEBUG_LCMS
}
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile )
{
#ifdef DEBUG_LCMS
g_message( "/^^^^^^^^^ %p::_setProfile(%s)", this,
( (profile) ? profile->colorProfile.c_str() : "<null>")
);
#endif // DEBUG_LCMS
bool profChanged = false;
if ( _prof && (!profile || (_profileName != profile->colorProfile) ) ) {
// Need to clear out the prior one
profChanged = true;
_profileName.clear();
_prof = 0;
_profChannelCount = 0;
} else if ( profile && !_prof ) {
profChanged = true;
}
for ( size_t i = 0; i < _compUI.size(); i++ ) {
gtk_widget_hide( _compUI[i]._label );
gtk_widget_hide( _compUI[i]._slider );
gtk_widget_hide( _compUI[i]._btn );
}
if ( profile ) {
_prof = SP_ACTIVE_DOCUMENT->profileManager->find(profile->colorProfile.c_str());
if ( _prof && (asICColorProfileClassSig(_prof->getProfileClass()) != cmsSigNamedColorClass) ) {
#if HAVE_LIBLCMS1
_profChannelCount = _cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) );
#elif HAVE_LIBLCMS2
_profChannelCount = cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) );
#endif
if ( profChanged ) {
std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace()));
for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i)
{
_compUI[i]._component = things[i];
}
for ( guint i = 0; i < _profChannelCount; i++ ) {
gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : "");
gtk_widget_set_tooltip_text( _compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" );
gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" );
sp_color_slider_set_colors( SP_COLOR_SLIDER(_compUI[i]._slider),
SPColor(0.0, 0.0, 0.0).toRGBA32(0xff),
SPColor(0.5, 0.5, 0.5).toRGBA32(0xff),
SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) );
/*
_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) );
g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel );
sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._adj );
gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), _compUI[i]._adj );
gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits );
*/
gtk_widget_show( _compUI[i]._label );
gtk_widget_show( _compUI[i]._slider );
gtk_widget_show( _compUI[i]._btn );
//gtk_adjustment_set_value( _compUI[i]._adj, 0.0 );
//gtk_adjustment_set_value( _compUI[i]._adj, val );
}
for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) {
gtk_widget_hide( _compUI[i]._label );
gtk_widget_hide( _compUI[i]._slider );
gtk_widget_hide( _compUI[i]._btn );
}
}
} else {
// Give up for now on named colors
_prof = 0;
}
}
#ifdef DEBUG_LCMS
g_message( "\\_________ %p::_setProfile()", this );
#endif // DEBUG_LCMS
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void ColorICCSelectorImpl::_updateSliders( gint ignore )
{
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
if ( _owner->_color.icc )
{
for ( guint i = 0; i < _profChannelCount; i++ ) {
gdouble val = 0.0;
if ( _owner->_color.icc->colors.size() > i ) {
if ( _compUI[i]._component.scale == 256 ) {
val = (_owner->_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_compUI[i]._component.scale);
} else {
val = _owner->_color.icc->colors[i] / static_cast<gdouble>(_compUI[i]._component.scale);
}
}
gtk_adjustment_set_value( _compUI[i]._adj, val );
}
if ( _prof ) {
if ( _prof->getTransfToSRGB8() ) {
for ( guint i = 0; i < _profChannelCount; i++ ) {
if ( static_cast<gint>(i) != ignore ) {
cmsUInt16Number* scratch = getScratch();
cmsUInt16Number filler[4] = {0, 0, 0, 0};
for ( guint j = 0; j < _profChannelCount; j++ ) {
filler[j] = 0x0ffff * ColorScales::getScaled( _compUI[j]._adj );
}
cmsUInt16Number* p = scratch;
for ( guint x = 0; x < 1024; x++ ) {
for ( guint j = 0; j < _profChannelCount; j++ ) {
if ( j == i ) {
*p++ = x * 0x0ffff / 1024;
} else {
*p++ = filler[j];
}
}
}
cmsHTRANSFORM trans = _prof->getTransfToSRGB8();
if ( trans ) {
cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 );
sp_color_slider_set_map( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._map );
}
}
}
}
}
}
#else
(void)ignore;
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
guint32 start = _owner->_color.toRGBA32( 0x00 );
guint32 mid = _owner->_color.toRGBA32( 0x7f );
guint32 end = _owner->_color.toRGBA32( 0xff );
sp_color_slider_set_colors( SP_COLOR_SLIDER(_slider), start, mid, end );
}
void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs )
{
// // TODO check this. It looks questionable:
// // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100
// if (adjustment->value > 0.0 && adjustment->value < 1.0) {
// gtk_adjustment_set_value( adjustment, floor ((adjustment->value) * adjustment->upper + 0.5) );
// }
#ifdef DEBUG_LCMS
g_message( "/^^^^^^^^^ %p::_adjustmentChanged()", cs );
#endif // DEBUG_LCMS
ColorICCSelector* iccSelector = static_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base);
if (iccSelector->_impl->_updating) {
return;
}
iccSelector->_impl->_updating = TRUE;
gint match = -1;
SPColor newColor( iccSelector->_color );
gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj );
if ( iccSelector->_impl->_adj == adjustment ) {
#ifdef DEBUG_LCMS
g_message("ALPHA");
#endif // DEBUG_LCMS
} else {
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
for ( size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++ ) {
if ( iccSelector->_impl->_compUI[i]._adj == adjustment ) {
match = i;
break;
}
}
if ( match >= 0 ) {
#ifdef DEBUG_LCMS
g_message(" channel %d", match );
#endif // DEBUG_LCMS
}
cmsUInt16Number tmp[4];
for ( guint i = 0; i < 4; i++ ) {
tmp[i] = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ) * 0x0ffff;
}
guchar post[4] = {0,0,0,0};
cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8();
if ( trans ) {
cmsDoTransform( trans, tmp, post, 1 );
}
SPColor other( SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255) );
other.icc = new SVGICCColor();
if ( iccSelector->_color.icc ) {
other.icc->colorProfile = iccSelector->_color.icc->colorProfile;
}
guint32 prior = iccSelector->_color.toRGBA32(255);
guint32 newer = other.toRGBA32(255);
if ( prior != newer ) {
#ifdef DEBUG_LCMS
g_message("Transformed color from 0x%08x to 0x%08x", prior, newer );
g_message(" ~~~~ FLIP");
#endif // DEBUG_LCMS
newColor = other;
newColor.icc->colors.clear();
for ( guint i = 0; i < iccSelector->_impl->_profChannelCount; i++ ) {
gdouble val = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj );
val *= iccSelector->_impl->_compUI[i]._component.scale;
if ( iccSelector->_impl->_compUI[i]._component.scale == 256 ) {
val -= 128;
}
newColor.icc->colors.push_back( val );
}
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
}
iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging );
iccSelector->_impl->_updateSliders( match );
iccSelector->_impl->_updating = FALSE;
#ifdef DEBUG_LCMS
g_message( "\\_________ %p::_adjustmentChanged()", cs );
#endif // DEBUG_LCMS
}
void ColorICCSelectorImpl::_sliderGrabbed( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ )
{
// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base);
// if (!iccSelector->_dragging) {
// iccSelector->_dragging = TRUE;
// iccSelector->_grabbed();
// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), iccSelector->_dragging );
// }
}
void ColorICCSelectorImpl::_sliderReleased( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ )
{
// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base);
// if (iccSelector->_dragging) {
// iccSelector->_dragging = FALSE;
// iccSelector->_released();
// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging );
// }
}
#ifdef DEBUG_LCMS
void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs )
#else
void ColorICCSelectorImpl::_sliderChanged( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ )
#endif // DEBUG_LCMS
{
#ifdef DEBUG_LCMS
g_message("Changed %p and %p", slider, cs );
#endif // DEBUG_LCMS
// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base);
// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging );
}
/*
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 :