/**
* @file
* Filter Effects dialog.
*/
/* Authors:
* Nicholas Bishop <nicholasbishop@gmail.org>
* Rodrigo Kumpera <kumpera@gmail.com>
* Felipe C. da S. Sanches <juca@members.fsf.org>
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
* insaner
*
* Copyright (C) 2007 Authors
*
* Released under GNU GPL. Read the file 'COPYING' for more information.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "dialog-manager.h"
#include <gtkmm/imagemenuitem.h>
#if GTK_CHECK_VERSION(3,0,0)
# include <gdkmm/devicemanager.h>
#endif
#include "ui/widget/spinbutton.h"
#include <glibmm/stringutils.h>
#include "desktop.h"
#include "dir-util.h"
#include "document.h"
#include "document-undo.h"
#include "filter-chemistry.h"
#include "filter-effects-dialog.h"
#include "filter-enums.h"
#include "inkscape.h"
#include "path-prefix.h"
#include "preferences.h"
#include "selection.h"
#include "filters/colormatrix.h"
#include "filters/componenttransfer.h"
#include "filters/componenttransfer-funcnode.h"
#include "filters/composite.h"
#include "filters/convolvematrix.h"
#include "filters/displacementmap.h"
#include "filters/distantlight.h"
#include "filters/gaussian-blur.h"
#include "filters/mergenode.h"
#include "filters/pointlight.h"
#include "filters/spotlight.h"
#include "sp-filter-primitive.h"
#include "style.h"
#include "svg/svg-color.h"
#include "svg/stringstream.h"
#include "ui/dialog/filedialog.h"
#include "verbs.h"
#include "xml/node-observer.h"
#include <sstream>
#include <iostream>
#include "selection-chemistry.h"
#include <gtkmm/checkbutton.h>
#include <gtkmm/colorbutton.h>
#include <gtkmm/scrolledwindow.h>
namespace Inkscape {
namespace UI {
namespace Dialog {
// Returns the number of inputs available for the filter primitive type
{
if(!prim)
return 0;
return 2;
else if(SP_IS_FEMERGE(prim)) {
// Return the number of feMergeNode connections plus an extra
return count;
}
else
return 1;
}
{
public:
const SPAttributeEnum a, char* tip_text)
AttrWidget(a, def),
{
if (tip_text) {
}
}
{
}
{
if(val) {
set_active(true);
else if(_false_val == val)
set_active(false);
} else {
}
}
private:
};
{
public:
AttrWidget(a, def)
{
if (tip_text) {
}
set_increments(step_inc, 0);
}
{
if(get_digits() == 0)
else
}
{
if(val){
} else {
}
}
};
{
public:
ComboWithTooltip<T>(T default_value, const Util::EnumDataConverter<T>& c, const SPAttributeEnum a = SP_ATTR_INVALID, char* tip_text = NULL)
{
if (tip_text) {
}
show_all();
}
{
delete combo;
}
{
return combo;
}
private:
};
// Contains an arbitrary number of spin buttons that use separate attributes
{
public:
double climb_rate, int digits, std::vector<SPAttributeEnum> attrs, std::vector<double> default_values, std::vector<char*> tip_text)
{
_spins.push_back(new SpinButtonAttr(lower, upper, step_inc, climb_rate, digits, attrs[i], default_values[i], tip_text[i]));
}
}
{
delete _spins[i];
}
{
return _spins;
}
private:
};
// Contains two spinbuttons that describe a NumberOptNumber
{
public:
{
if (tt1) {
}
if (tt2) {
}
pack_start(_s1, false, false);
pack_start(_s2, false, false);
}
{
return _s1;
}
{
return _s2;
}
{
if(_s1.get_digits() == 0) {
}
}
{
if(val) {
} else {
}
}
private:
};
{
public:
: AttrWidget(a, def)
{
if (tip_text) {
}
#if WITH_GTKMM_3_0
#else
#endif
}
// Returns the color in 'rgb(r,g,b)' form.
{
// no doubles here, so we can use the standard string stream.
#if WITH_GTKMM_3_0
const int r = c.get_red_u() / 257, g = c.get_green_u() / 257, b = c.get_blue_u() / 257;//TO-DO: verify this. This sounds a lot strange! shouldn't it be 256?
#else
const int r = c.get_red() / 257, g = c.get_green() / 257, b = c.get_blue() / 257;//TO-DO: verify this. This sounds a lot strange! shouldn't it be 256?
#endif
}
{
guint32 i = 0;
if(val) {
} else {
}
#if WITH_GTKMM_3_0
#else
#endif
}
};
// Used for tableValue in feComponentTransfer
{
public:
: AttrWidget(a)
{
if (tip_text) {
}
}
// No validity checking is done
{
return get_text();
}
{
if(val) {
} else {
set_text( "" );
}
}
};
{
public:
: AttrWidget(a), _locked(false)
{
_tree.set_headers_visible(false);
if (tip_text) {
}
}
{
}
return vec;
}
{
unsigned i = 0;
if(i >= v.size())
return;
++i;
}
}
}
{
// use SVGOStringStream to output SVG-compatible doubles
}
}
}
{
if(o) {
if(SP_IS_FECONVOLVEMATRIX(o)) {
if(cols > 5)
cols = 5;
}
else if(SP_IS_FECOLORMATRIX(o))
}
}
private:
{
public:
{
}
};
{
if(_locked)
return;
if(SP_IS_FECOLORMATRIX(o))
else if(SP_IS_FECONVOLVEMATRIX(o))
else
return;
if(o) {
int ndx = 0;
for(int i = 0; i < cols; ++i) {
dynamic_cast<Gtk::CellRendererText*>(
}
for(int r = 0; r < rows; ++r) {
// Default to identity matrix
}
}
}
{
_locked = true;
signal_attr_changed()();
_locked = false;
}
bool _locked;
};
// Displays a matrix or a slider for feColorMatrix
{
public:
// TRANSLATORS: this dialog is accessible via menu Filters - Filter editor
_matrix(SP_ATTR_VALUES, _("This matrix determines a linear transform on color space. Each line affects one of the color components. Each column determines how much of each color component from the input is passed to the output. The last column does not depend on input colors, so can be used to adjust a constant component value.")),
_use_stored(false),
_angle_store(0)
{
_saturation.show();
_label.set_sensitive(false);
}
{
if(SP_IS_FECOLORMATRIX(o)) {
remove();
case COLORMATRIX_SATURATE:
if(_use_stored)
else
break;
case COLORMATRIX_HUEROTATE:
if(_use_stored)
else
break;
break;
case COLORMATRIX_MATRIX:
default:
if(_use_stored)
else
break;
}
_use_stored = true;
}
}
{
if(w == &_label)
return "";
else
return dynamic_cast<const AttrWidget*>(w)->get_as_attribute();
}
void clear_store()
{
_use_stored = false;
}
private:
void update_store()
{
if(w == &_matrix)
else if(w == &_saturation)
else if(w == &_angle)
}
// Store separate values for the different color modes
bool _use_stored;
double _saturation_store;
double _angle_store;
};
//Displays a chooser for feImage input
//It may be a filename or the id for an SVG Element
//described in xlink:href syntax
{
public:
: AttrWidget(a)
{
pack_start(_entry, false, false);
pack_start(_fromFile, false, false);
pack_start(_fromSVGElement, false, false);
_fromSVGElement.signal_clicked().connect(sigc::mem_fun(*this, &FileOrElementChooser::select_svg_element));
show_all();
}
// Returns the element in xlink:href form.
{
}
{
if(val) {
} else {
}
}
_desktop = d;
}
private:
void select_svg_element(){
}
void select_file(){
//# Get the current directory for finding files
//# Test if the open_path directory exists
open_path = "";
//# If no open path, default to our home directory
{
open_path = g_get_home_dir();
}
//# Create a dialog if we don't already have one
if (!selectFeImageFileInstance) {
*_desktop->getToplevel(),
(char const *)_("Select an image to be used as feImage input"));
}
//# Show the dialog
if (!success)
return;
//# User selected something. Get name and type
if ( newFileName.size() > 0)
else
g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
}
return;
}
};
{
public:
{
for(int i = 0; i < _max_types; ++i) {
b.pack_start(*_groups[i], false, false);
}
//_current_type = 0; If set to 0 then update_and_show() fails to update properly.
}
~Settings()
{
for(int i = 0; i < _max_types; ++i) {
delete _groups[i];
for(unsigned j = 0; j < _attrwidgets[i].size(); ++j)
delete _attrwidgets[i][j];
}
}
// Show the active settings group and update all the AttrWidgets with new values
{
if(t != _current_type) {
type(t);
}
if(t >= 0) {
}
_dialog.set_attrs_locked(true);
_dialog.set_attrs_locked(false);
}
int get_current_type() const
{
return _current_type;
}
void type(const int t)
{
_current_type = t;
}
void add_no_params()
{
Gtk::Label* lbl = Gtk::manage(new Gtk::Label(_("This SVG filter effect does not require any parameters.")));
}
void add_notimplemented()
{
Gtk::Label* lbl = Gtk::manage(new Gtk::Label(_("This SVG filter effect is not yet implemented in Inkscape.")));
}
// LightSource
// Component Transfer Values
ComponentTransferValues* add_componenttransfervalues(const Glib::ustring& label, SPFeFuncNode::Channel channel);
// CheckButton
{
return cb;
}
// ColorButton
ColorButton* add_color(unsigned int def, const SPAttributeEnum attr, const Glib::ustring& label, char* tip_text = NULL)
{
return col;
}
// Matrix
{
return conv;
}
// ColorMatrixValues
{
return cmv;
}
// SpinScale
const double lo, const double hi, const double step_inc, const double climb, const int digits, char* tip_text = NULL)
{
return spinslider;
}
// DualSpinScale
{
DualSpinScale* dss = new DualSpinScale("", "", lo, lo, hi, step_inc, climb, digits, attr, tip_text1, tip_text2);
return dss;
}
// DualSpinButton
DualSpinButton* add_dualspinbutton(char* defalt_value, const SPAttributeEnum attr, const Glib::ustring& label,
{
DualSpinButton* dsb = new DualSpinButton(defalt_value, lo, hi, step_inc, climb, digits, attr, tip1, tip2);
return dsb;
}
// MultiSpinButton
MultiSpinButton* add_multispinbutton(double def1, double def2, const SPAttributeEnum attr1, const SPAttributeEnum attr2,
{
MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
return msb;
}
MultiSpinButton* add_multispinbutton(double def1, double def2, double def3, const SPAttributeEnum attr1, const SPAttributeEnum attr2,
const double hi, const double step_inc, const double climb, const int digits, char* tip1 = NULL, char* tip2 = NULL, char* tip3 = NULL)
{
MultiSpinButton* msb = new MultiSpinButton(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
return msb;
}
// FileOrElementChooser
{
return foech;
}
// ComboBoxEnum
{
return combo->get_attrwidget();
}
// Entry
{
return entry;
}
private:
{
}
/* Adds a new settings widget using the specified label. The label will be formatted with a colon
and all widgets within the setting group are aligned automatically. */
{
if(label != "") {
}
hb->pack_start(*w);
w->show();
}
};
{
public:
_dialog(d),
_settings(d, _box, sigc::mem_fun(*this, &ComponentTransferValues::set_func_attr), COMPONENTTRANSFER_TYPE_ERROR),
{
//_settings.type(COMPONENTTRANSFER_TYPE_IDENTITY);
}
// FuncNode can be in any order so we must search to find correct one.
{
bool found = false;
found = true;
break;
}
}
if( !found )
return funcNode;
}
{
}
// Set new type and update widget visibility
{
// See componenttransfer.cpp
if(SP_IS_FECOMPONENTTRANSFER(o)) {
if( _funcNode ) {
} else {
// Create <funcNode>
if(prim) {
switch(_channel) {
case SPFeFuncNode::R:
break;
case SPFeFuncNode::G:
break;
case SPFeFuncNode::B:
break;
case SPFeFuncNode::A:
break;
}
//XML Tree being used directly here while it shouldn't be.
// Now we should find it!
if( _funcNode ) {
} else {
//std::cout << "ERROR ERROR: feFuncX not found!" << std::endl;
}
}
}
update();
}
}
private:
void on_type_changed()
{
if(prim) {
update();
}
}
void update()
{
}
}
public:
{
return "";
}
};
// Settings for the three light source objects
{
public:
_dialog(d),
_settings(d, _box, sigc::mem_fun(_dialog, &FilterEffectsDialog::set_child_attr_direct), LIGHT_ENDSOURCE),
_locked(false)
{
_light_source.signal_changed().connect(sigc::mem_fun(*this, &LightSourceControl::on_source_changed));
// FIXME: these range values are complete crap
_settings.add_spinscale(0, SP_ATTR_AZIMUTH, _("Azimuth"), 0, 360, 1, 1, 0, _("Direction angle for the light source on the XY plane, in degrees"));
_settings.add_spinscale(0, SP_ATTR_ELEVATION, _("Elevation"), 0, 360, 1, 1, 0, _("Direction angle for the light source on the YZ plane, in degrees"));
_settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0, SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location:"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
_settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0, SP_ATTR_X, SP_ATTR_Y, SP_ATTR_Z, _("Location:"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
_settings.add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, /*default z:*/ (double) 0,
_("Points At"), -99999, 99999, 1, 100, 0, _("X coordinate"), _("Y coordinate"), _("Z coordinate"));
_settings.add_spinscale(1, SP_ATTR_SPECULAREXPONENT, _("Specular Exponent"), 1, 100, 1, 1, 0, _("Exponent value controlling the focus for the light source"));
//TODO: here I have used 100 degrees as default value. But spec says that if not specified, no limiting cone is applied. So, there should be a way for the user to set a "no limiting cone" option.
_settings.add_spinscale(100, SP_ATTR_LIMITINGCONEANGLE, _("Cone Angle"), 1, 100, 1, 1, 0, _("This is the angle between the spot light axis (i.e. the axis between the light source and the point to which it is pointing at) and the spot light cone. No light is projected outside this cone."));
}
{
return _box;
}
protected:
{
return "";
}
{
if(_locked)
return;
_locked = true;
else if(SP_IS_FEPOINTLIGHT(child))
else if(SP_IS_FESPOTLIGHT(child))
else
update();
_locked = false;
}
private:
void on_source_changed()
{
if(_locked)
return;
if(prim) {
_locked = true;
// Check if the light source type has changed
if(child)
//XML Tree being used directly here while it shouldn't be.
if(ls != -1) {
//XML Tree being used directly here while it shouldn't be.
}
update();
}
_locked = false;
}
}
void update()
{
}
bool _locked;
};
// ComponentTransferValues
FilterEffectsDialog::ComponentTransferValues* FilterEffectsDialog::Settings::add_componenttransfervalues(const Glib::ustring& label, SPFeFuncNode::Channel channel)
{
return ct;
}
{
return ls;
}
{
return menu;
}
/*** FilterModifier ***/
_deskTrack(),
_dialog(d),
{
pack_start(*sw);
pack_start(_add, false, false);
_cell_toggle.set_active(true);
if(col)
signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::on_name_edited));
_list.set_reorderable(true);
_menu->accelerate(*this);
_list.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FilterModifier::on_filter_selection_changed));
desktopChangeConn = _deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &FilterModifier::setTargetDesktop) );
}
{
}
{
if (_desktop) {
}
if (desktop) {
_selectChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &FilterModifier::on_change_selection)));
_selectModifiedConn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &FilterModifier::on_modified_selection)));
}
_doc_replaced = desktop->connectDocumentReplaced( sigc::mem_fun(*this, &FilterModifier::on_document_replaced));
_resource_changed = desktop->getDocument()->connectResourcesChanged("filter",sigc::mem_fun(*this, &FilterModifier::update_filters));
}
}
}
// When the document changes, update connection to resources
void FilterEffectsDialog::FilterModifier::on_document_replaced(SPDesktop * /*desktop*/, SPDocument *document)
{
if (_resource_changed) {
}
if (document)
{
_resource_changed = document->connectResourcesChanged("filter",sigc::mem_fun(*this, &FilterModifier::update_filters));
}
}
// When the selection changes, show the active filter(s) in the dialog
{
}
{
if (flags & ( SP_OBJECT_MODIFIED_FLAG |
}
}
// Update each filter's sel property based on the current object selection;
// If the filter is not used by any selected object, sel = 0,
// otherwise sel is set to the total number of filters in use by selected objects
// If only one filter is in use, it is selected
{
if (!sel) {
return;
}
continue;
}
} else {
}
}
// If only one filter is in use by the selection, select it
if (size == 1) {
}
} else {
}
}
}
{
}
void FilterEffectsDialog::FilterModifier::on_name_edited(const Glib::ustring& path, const Glib::ustring& text)
{
if(iter) {
if(iter)
}
}
bool FilterEffectsDialog::FilterModifier::on_filter_move(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int /*x*/, int /*y*/, guint /*time*/) {
//const Gtk::TreeModel::Path& /*path*/) {
/* The code below is bugged. Use of "object->getRepr()->setPosition(0)" is dangerous!
Writing back the reordered list to XML (reordering XML nodes) should be implemented differently.
Note that the dialog does also not update its list of filters when the order is manually changed
using the XML dialog
for(Gtk::TreeModel::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
SPObject* object = (*i)[_columns.filter];
if(object && object->getRepr()) ;
object->getRepr()->setPosition(0);
}
*/
return false;
}
{
if(iter) {
/* If this filter is the only one used in the selection, unset it */
filter = 0;
if (filter) {
} else {
::remove_filter(item, false);
}
}
}
}
{
}
}
/* Add all filters in the document to the combobox.
Keeps the same selection if possible, otherwise selects the first element */
{
}
}
{
if(_list.get_selection()) {
if(i)
}
return 0;
}
{
if(filter) {
break;
}
}
}
}
{
}
}
{
}
{
if(filter) {
// Delete all references to this filter
std::vector<SPItem*> all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y);
if (!SP_IS_ITEM(*i)) {
continue;
}
continue;
}
::remove_filter(item, false);
}
}
}
//XML Tree being used directly here while it shouldn't be.
}
}
{
if (filter) {
}
}
{
_list.set_cursor(_model->get_path(_list.get_selection()->get_selected()), *_list.get_column(1), true);
}
_primitive(*this, "primitive", 0),
_text_width(0)
{}
{
return _primitive.get_proxy();
}
#if WITH_GTKMM_3_0
int& minimum_width,
int& natural_width) const
{
minimum_width = natural_width = size * primlist.primitive_count() + primlist.get_input_type_width() * 6;
}
void FilterEffectsDialog::CellRendererConnection::get_preferred_width_for_height_vfunc(Gtk::Widget& widget,
int /* height */,
int& minimum_width,
int& natural_width) const
{
}
int& minimum_height,
int& natural_height) const
{
// Scale the height depending on the number of inputs, unless it's
// the first primitive, in which case there are no connections
}
void FilterEffectsDialog::CellRendererConnection::get_preferred_height_for_width_vfunc(Gtk::Widget& widget,
int /* width */,
int& minimum_height,
int& natural_height) const
{
}
#else
{
if(x_offset)
(*x_offset) = 0;
if(y_offset)
(*y_offset) = 0;
if(width)
if(height) {
// Scale the height depending on the number of inputs, unless it's
// the first primitive, in which case there are no connections
}
}
#endif
/*** PrimitiveList ***/
: _dialog(d),
_in_drag(0),
{
#if WITH_GTKMM_3_0
#else
#endif
set_reorderable(true);
get_column(0)->set_resizable(true);
get_selection()->signal_changed().connect(sigc::mem_fun(*this, &PrimitiveList::on_primitive_selection_changed));
init_text();
if(col)
}
// width needed to render the FilterPrimitiveInput labels.
{
// Set up a vertical context+layout
// Store the maximum height and width of the an input type label
// for later use in drawing and measuring.
for(unsigned int i = 0; i < FPInputConverter._length; ++i) {
if(fonth > _input_type_width)
if (fontw > _input_type_height)
}
}
{
return _signal_primitive_changed;
}
{
}
/* Add all filter primitives in the current to the list.
Keeps the same selection if possible, otherwise selects the first element */
{
if(f) {
bool active_found = false;
if(prim) {
//XML Tree being used directly here while it shouldn't be.
}
if(prim == active_prim) {
active_found = true;
}
}
}
if (height == -1) {
// Need to account for the height of the input type text (rotated text) as well as the
// column headers. Input type text height determined in init_text() by measuring longest
// string. Column header height determined by mapping y coordinate of visible
// rectangle to widget coordinates.
}
}
else {
}
}
{
}
{
if(i)
}
return 0;
}
{
get_selection()->select(i);
}
}
{
if(prim) {
//XML Tree being used directly here while it shouldn't be.
_("Remove filter primitive"));
update();
}
}
#if !WITH_GTKMM_3_0
{
bool result = false;
if (get_is_drawable())
{
}
return result;
}
#endif
{
#if GTK_CHECK_VERSION(3,0,0)
// In GTK+ 3, the draw function receives the widget window, not the
// bin_window (i.e., just the area under the column headers). We
// therefore translate the origin of our coordinate system to account for this
#else
#endif
int text_start_x = 0;
if(row) {
text_start_x = rct.get_x() + rct.get_width() - get_input_type_width() * FPInputConverter._length + 1;
for(unsigned int i = 0; i < FPInputConverter._length; ++i) {
const int x = text_start_x + get_input_type_width() * i;
#if GTK_CHECK_VERSION(3,0,0)
cr->fill_preserve();
#else
cr->fill_preserve();
#endif
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
}
}
int row_index = 0;
// Check mouse state
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
// Outline the bottom of the connection area
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
// Side outline
int con_drag_y = 0;
int con_drag_x = 0;
bool inside;
if(SP_IS_FEMERGE(row_prim)) {
for(int i = 0; i < inputs; ++i) {
#if GTK_CHECK_VERSION(3,0,0)
&mid_color :
#else
#endif
if(_in_drag == (i + 1))
{
}
{
}
}
}
else {
// Draw "in" shape
#if GTK_CHECK_VERSION(3,0,0)
&mid_color :
#else
#endif
// Draw "in" connection
{
}
if(inputs == 2) {
// Draw "in2" shape
if(_in_drag == 2)
{
}
#if GTK_CHECK_VERSION(3,0,0)
&mid_color :
#else
#endif
// Draw "in2" connection
{
}
}
}
// Draw drag connection
}
}
return true;
}
const int row_count)
{
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
int src_id = 0;
// Draw straight connection to a standard input
// Draw a lighter line for an implicit connection to a standard input
if(use_default && is_first)
#if GTK_CHECK_VERSION(3,0,0)
#else
#endif
else
cr->fill_preserve();
}
else {
// Draw an 'L'-shaped connection to another filter primitive
// If no connection is specified, draw a light connection to the previous primitive
if(use_default) {
--res;
}
if(res) {
// Draw a bevelled 'L'-shaped connection
}
}
}
// Draw the triangular outline of the connection node, and fill it
// if desired
void FilterEffectsDialog::PrimitiveList::draw_connection_node(const Cairo::RefPtr<Cairo::Context>& cr,
const bool fill)
{
}
// Creates a triangle outline of the connection node and returns true if (x,y) is inside the node
bool FilterEffectsDialog::PrimitiveList::do_connection_node(const Gtk::TreeIter& row, const int input,
{
}
{
int image = 0;
if(SP_IS_FEMERGE(prim)) {
int c = 0;
bool found = false;
if(c == attr && SP_IS_FEMERGENODE(o)) {
found = true;
}
}
if(!found)
return target;
}
else {
if(attr == SP_ATTR_IN)
else if(attr == SP_ATTR_IN2) {
if(SP_IS_FEBLEND(prim))
else if(SP_IS_FECOMPOSITE(prim))
else if(SP_IS_FEDISPLACEMENTMAP(prim))
else
return target;
}
else
return target;
}
if(image >= 0) {
i != start; ++i) {
target = i;
}
return target;
}
else if(image < -1) {
return start;
}
return target;
}
{
int i = 0;
return i;
}
{
const int x = (int)e->x, y = (int)e->y;
_drag_prim = 0;
for(int i = 0; i < icnt; ++i) {
_in_drag = i + 1;
break;
}
}
queue_draw();
}
if(_in_drag) {
_scroll_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &PrimitiveList::on_scroll_timeout), 150);
_autoscroll_x = 0;
_autoscroll_y = 0;
return true;
}
else
}
{
// When autoscrolling during a connection drag, set the speed based on
// where the mouse is in relation to the edges.
if(e->y < vis_y)
_autoscroll_y = -speed;
else if(e->y > top)
else
_autoscroll_y = 0;
// horizontal scrolling
_autoscroll_x = -speed;
else if(e2 > right_edge)
else
_autoscroll_x = 0;
queue_draw();
}
{
if (src < 0) {
src = 0;
}
}
else {
// Ensure that the target comes before the selected primitive
if(iter == target_iter) {
// Make sure the target has a result
if(!gres) {
}
else
break;
}
}
}
if(SP_IS_FEMERGE(prim)) {
int c = 1;
bool handled = false;
if(c == _in_drag && SP_IS_FEMERGENODE(o)) {
// If input is null, delete it
if(!in_val) {
//XML Tree being used directly here while it shouldn't be.
sp_repr_unparent(o->getRepr());
_("Remove merge node"));
}
else
handled = true;
}
}
// Add new input?
//XML Tree being used directly here while it shouldn't be.
}
}
else {
if(_in_drag == 1)
else if(_in_drag == 2)
}
}
_in_drag = 0;
queue_draw();
}
return true;
}
else
}
// Checks all of prim's inputs, removes any that use result
{
}
if (SP_IS_FEBLEND(prim)) {
}
} else if (SP_IS_FECOMPOSITE(prim)) {
}
} else if (SP_IS_FEDISPLACEMENTMAP(prim)) {
}
}
}
}
{
bool before = true;
before = false;
else {
if(before)
else
}
}
}
// Reorder the filter primitives to match the list order
{
int ndx = 0;
break;
}
}
break;
}
}
}
// If a connection is dragged towards the top or bottom of the list, the list should scroll to follow.
{
if(_autoscroll_y) {
#if WITH_GTKMM_3_0
Glib::RefPtr<Gtk::Adjustment> a = dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_vadjustment();
double v = a->get_value() + _autoscroll_y;
if(v < 0)
v = 0;
if(v > a->get_upper() - a->get_page_size())
v = a->get_upper() - a->get_page_size();
a->set_value(v);
#else
double v = a.get_value() + _autoscroll_y;
if(v < 0)
v = 0;
if(v > a.get_upper() - a.get_page_size())
v = a.get_upper() - a.get_page_size();
a.set_value(v);
#endif
queue_draw();
}
if(_autoscroll_x) {
#if WITH_GTKMM_3_0
Glib::RefPtr<Gtk::Adjustment> a_h = dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_hadjustment();
if(h < 0)
h = 0;
#else
if(h < 0)
h = 0;
#endif
queue_draw();
}
return true;
}
{
}
{
// Maximum font height calculated in initText() and stored in _input_type_width.
// Add 2 to font height to account for rectangle around text.
return _input_type_width + 2;
}
/*** FilterEffectsDialog ***/
_add_primitive(_("Add Effect:")),
_settings_initialized(false),
_locked(false),
_attr_lock(false),
_filter_modifier(*this),
_primitive_list(*this)
{
_settings = new Settings(*this, _settings_tab1, sigc::mem_fun(*this, &FilterEffectsDialog::set_attr_direct),
_filter_general_settings = new Settings(*this, _settings_tab2, sigc::mem_fun(*this, &FilterEffectsDialog::set_filternode_attr),
1);
// Initialize widget hierarchy
#if WITH_GTKMM_3_0
#else
#endif
_infobox_icon.set_alignment(0, 0);
_infobox_desc.set_alignment(0, 0);
_infobox_desc.set_line_wrap(true);
//_sw_infobox->set_size_request(-1, -1);
//vb_prims->set_size_request(-1, 50);
// al_settings->set_padding(0, 0, 12, 0);
// fr_settings->set_shadow_type(Gtk::SHADOW_NONE);
// ((Gtk::Label*)fr_settings->get_label_widget())->set_use_markup();
_primitive_list.set_menu(create_popup_menu(*this, sigc::mem_fun(*this, &FilterEffectsDialog::duplicate_primitive),
}
{
delete _settings;
delete _filter_general_settings;
}
{
_locked = l;
}
{
}
{
// TODO: Find better range/climb-rate/digits values for the SpinScales,
// most of the current values are complete guesses!
_empty_settings.set_sensitive(false);
_no_filter_selected.set_sensitive(false);
_settings_initialized = true;
_filter_general_settings->add_multispinbutton(/*default x:*/ (double) -0.1, /*default y:*/ (double) -0.1, SP_ATTR_X, SP_ATTR_Y, _("Coordinates:"), -100, 100, 0.01, 0.1, 2, _("X coordinate of the left corners of filter effects region"), _("Y coordinate of the upper corners of filter effects region"));
_filter_general_settings->add_multispinbutton(/*default width:*/ (double) 1.2, /*default height:*/ (double) 1.2, SP_ATTR_WIDTH, SP_ATTR_HEIGHT, _("Dimensions:"), 0, 1000, 0.01, 0.1, 2, _("Width of filter effects region"), _("Height of filter effects region"));
ComboBoxEnum<FilterColorMatrixType>* colmat = _settings->add_combo(COLORMATRIX_MATRIX, SP_ATTR_TYPE, _("Type:"), ColorMatrixTypeConverter, _("Indicates the type of matrix operation. The keyword 'matrix' indicates that a full 5x4 matrix of values will be provided. The other keywords represent convenience shortcuts to allow commonly used color operations to be performed without specifying a complete matrix."));
colmat->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::update_color_matrix));
_k1 = _settings->add_spinscale(0, SP_ATTR_K1, _("K1:"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
_k2 = _settings->add_spinscale(0, SP_ATTR_K2, _("K2:"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
_k3 = _settings->add_spinscale(0, SP_ATTR_K3, _("K3:"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
_k4 = _settings->add_spinscale(0, SP_ATTR_K4, _("K4:"), -10, 10, 0.1, 0.01, 2, _("If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
_convolve_order = _settings->add_dualspinbutton((char*)"3", SP_ATTR_ORDER, _("Size:"), 1, 5, 1, 1, 0, _("width of the convolve matrix"), _("height of the convolve matrix"));
_convolve_target = _settings->add_multispinbutton(/*default x:*/ (double) 0, /*default y:*/ (double) 0, SP_ATTR_TARGETX, SP_ATTR_TARGETY, _("Target:"), 0, 4, 1, 1, 0, _("X coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."), _("Y coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."));
//TRANSLATORS: for info on "Kernel", see http://en.wikipedia.org/wiki/Kernel_(matrix)
_convolve_matrix = _settings->add_matrix(SP_ATTR_KERNELMATRIX, _("Kernel:"), _("This matrix describes the convolve operation that is applied to the input image in order to calculate the pixel colors at the output. Different arrangements of values in this matrix result in various possible visual effects. An identity matrix would lead to a motion blur effect (parallel to the matrix diagonal) while a matrix filled with a constant non-zero value would lead to a common blur effect."));
_convolve_order->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::convolve_order_changed));
_settings->add_spinscale(0, SP_ATTR_DIVISOR, _("Divisor:"), 0, 1000, 1, 0.1, 2, _("After applying the kernelMatrix to the input image to yield a number, that number is divided by divisor to yield the final destination color value. A divisor that is the sum of all the matrix values tends to have an evening effect on the overall color intensity of the result."));
_settings->add_spinscale(0, SP_ATTR_BIAS, _("Bias:"), -10, 10, 1, 0.01, 1, _("This value is added to each component. This is useful to define a constant value as the zero response of the filter."));
_settings->add_combo(CONVOLVEMATRIX_EDGEMODE_DUPLICATE, SP_ATTR_EDGEMODE, _("Edge Mode:"), ConvolveMatrixEdgeModeConverter, _("Determines how to extend the input image as necessary with color values so that the matrix operations can be applied when the kernel is positioned at or near the edge of the input image."));
_settings->add_checkbutton(false, SP_ATTR_PRESERVEALPHA, _("Preserve Alpha"), "true", "false", _("If set, the alpha channel won't be altered by this filter primitive."));
_settings->add_color(/*default: white*/ 0xffffffff, SP_PROP_LIGHTING_COLOR, _("Diffuse Color:"), _("Defines the color of the light source"));
_settings->add_spinscale(1, SP_ATTR_SURFACESCALE, _("Surface Scale:"), -5, 5, 0.01, 0.001, 3, _("This value amplifies the heights of the bump map defined by the input alpha channel"));
_settings->add_spinscale(1, SP_ATTR_DIFFUSECONSTANT, _("Constant:"), 0, 5, 0.1, 0.01, 2, _("This constant affects the Phong lighting model."));
_settings->add_dualspinscale(SP_ATTR_KERNELUNITLENGTH, _("Kernel Unit Length:"), 0.01, 10, 1, 0.01, 1);
_settings->add_spinscale(0, SP_ATTR_SCALE, _("Scale:"), 0, 100, 1, 0.01, 1, _("This defines the intensity of the displacement effect."));
_settings->add_combo(DISPLACEMENTMAP_CHANNEL_ALPHA, SP_ATTR_XCHANNELSELECTOR, _("X displacement:"), DisplacementMapChannelConverter, _("Color component that controls the displacement in the X direction"));
_settings->add_combo(DISPLACEMENTMAP_CHANNEL_ALPHA, SP_ATTR_YCHANNELSELECTOR, _("Y displacement:"), DisplacementMapChannelConverter, _("Color component that controls the displacement in the Y direction"));
_settings->add_color(/*default: black*/ 0, SP_PROP_FLOOD_COLOR, _("Flood Color:"), _("The whole filter region will be filled with this color."));
_settings->add_dualspinscale(SP_ATTR_STDDEVIATION, _("Standard Deviation:"), 0.01, 100, 1, 0.01, 2, _("The standard deviation for the blur operation."));
_settings->add_combo(MORPHOLOGY_OPERATOR_ERODE, SP_ATTR_OPERATOR, _("Operator:"), MorphologyOperatorConverter, _("Erode: performs \"thinning\" of input image.\nDilate: performs \"fattenning\" of input image."));
_settings->add_spinscale(0, SP_ATTR_DX, _("Delta X:"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted to the right"));
_settings->add_spinscale(0, SP_ATTR_DY, _("Delta Y:"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted downwards"));
_settings->add_color(/*default: white*/ 0xffffffff, SP_PROP_LIGHTING_COLOR, _("Specular Color:"), _("Defines the color of the light source"));
_settings->add_spinscale(1, SP_ATTR_SURFACESCALE, _("Surface Scale:"), -5, 5, 0.1, 0.01, 2, _("This value amplifies the heights of the bump map defined by the input alpha channel"));
_settings->add_spinscale(1, SP_ATTR_SPECULARCONSTANT, _("Constant:"), 0, 5, 0.1, 0.01, 2, _("This constant affects the Phong lighting model."));
_settings->add_spinscale(1, SP_ATTR_SPECULAREXPONENT, _("Exponent:"), 1, 50, 1, 0.01, 1, _("Exponent for specular term, larger is more \"shiny\"."));
_settings->add_dualspinscale(SP_ATTR_KERNELUNITLENGTH, _("Kernel Unit Length:"), 0.01, 10, 1, 0.01, 1);
// _settings->add_checkbutton(false, SP_ATTR_STITCHTILES, _("Stitch Tiles"), "stitch", "noStitch");
_settings->add_combo(TURBULENCE_TURBULENCE, SP_ATTR_TYPE, _("Type:"), TurbulenceTypeConverter, _("Indicates whether the filter primitive should perform a noise or turbulence function."));
_settings->add_spinscale(0, SP_ATTR_SEED, _("Seed:"), 0, 1000, 1, 1, 0, _("The starting number for the pseudo random number generator."));
}
{
if(filter) {
}
}
{
_sw_infobox->show();
} else {
_sw_infobox->hide();
}
case(NR_FILTER_BLEND):
_infobox_desc.set_markup(_("The <b>feBlend</b> filter primitive provides 4 image blending modes: screen, multiply, darken and lighten."));
break;
case(NR_FILTER_COLORMATRIX):
_infobox_desc.set_markup(_("The <b>feColorMatrix</b> filter primitive applies a matrix transformation to color of each rendered pixel. This allows for effects like turning object to grayscale, modifying color saturation and changing color hue."));
break;
case(NR_FILTER_COMPONENTTRANSFER):
_infobox_desc.set_markup(_("The <b>feComponentTransfer</b> filter primitive manipulates the input's color components (red, green, blue, and alpha) according to particular transfer functions, allowing operations like brightness and contrast adjustment, color balance, and thresholding."));
break;
case(NR_FILTER_COMPOSITE):
_infobox_desc.set_markup(_("The <b>feComposite</b> filter primitive composites two images using one of the Porter-Duff blending modes or the arithmetic mode described in SVG standard. Porter-Duff blending modes are essentially logical operations between the corresponding pixel values of the images."));
break;
case(NR_FILTER_CONVOLVEMATRIX):
_infobox_desc.set_markup(_("The <b>feConvolveMatrix</b> lets you specify a Convolution to be applied on the image. Common effects created using convolution matrices are blur, sharpening, embossing and edge detection. Note that while gaussian blur can be created using this filter primitive, the special gaussian blur primitive is faster and resolution-independent."));
break;
case(NR_FILTER_DIFFUSELIGHTING):
_infobox_desc.set_markup(_("The <b>feDiffuseLighting</b> and feSpecularLighting filter primitives create \"embossed\" shadings. The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer."));
break;
case(NR_FILTER_DISPLACEMENTMAP):
_infobox_desc.set_markup(_("The <b>feDisplacementMap</b> filter primitive displaces the pixels in the first input using the second input as a displacement map, that shows from how far the pixel should come from. Classical examples are whirl and pinch effects."));
break;
case(NR_FILTER_FLOOD):
_infobox_desc.set_markup(_("The <b>feFlood</b> filter primitive fills the region with a given color and opacity. It is usually used as an input to other filters to apply color to a graphic."));
break;
case(NR_FILTER_GAUSSIANBLUR):
_infobox_desc.set_markup(_("The <b>feGaussianBlur</b> filter primitive uniformly blurs its input. It is commonly used together with feOffset to create a drop shadow effect."));
break;
case(NR_FILTER_IMAGE):
_infobox_desc.set_markup(_("The <b>feImage</b> filter primitive fills the region with an external image or another part of the document."));
break;
case(NR_FILTER_MERGE):
_infobox_desc.set_markup(_("The <b>feMerge</b> filter primitive composites several temporary images inside the filter primitive to a single image. It uses normal alpha compositing for this. This is equivalent to using several feBlend primitives in 'normal' mode or several feComposite primitives in 'over' mode."));
break;
case(NR_FILTER_MORPHOLOGY):
_infobox_desc.set_markup(_("The <b>feMorphology</b> filter primitive provides erode and dilate effects. For single-color objects erode makes the object thinner and dilate makes it thicker."));
break;
case(NR_FILTER_OFFSET):
_infobox_desc.set_markup(_("The <b>feOffset</b> filter primitive offsets the image by an user-defined amount. For example, this is useful for drop shadows, where the shadow is in a slightly different position than the actual object."));
break;
case(NR_FILTER_SPECULARLIGHTING):
_infobox_desc.set_markup(_("The <b>feDiffuseLighting</b> and <b>feSpecularLighting</b> filter primitives create \"embossed\" shadings. The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer."));
break;
case(NR_FILTER_TILE):
_infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with an input graphic. The source tile is defined by the filter primitive subregion of the input."));
break;
case(NR_FILTER_TURBULENCE):
_infobox_desc.set_markup(_("The <b>feTurbulence</b> filter primitive renders Perlin noise. This kind of noise is useful in simulating several nature phenomena like clouds, fire and smoke and in generating complex textures like marble or granite."));
break;
default:
g_assert(false);
break;
}
//_infobox_icon.set_pixel_size(96);
}
{
DocumentUndo::done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter primitive"));
}
}
{
_convolve_target->get_spinbuttons()[0]->get_adjustment()->set_upper(_convolve_order->get_spinbutton1().get_value() - 1);
_convolve_target->get_spinbuttons()[1]->get_adjustment()->set_upper(_convolve_order->get_spinbutton2().get_value() - 1);
}
{
set_attr(_primitive_list.get_selected(), input->get_attribute(), input->get_as_attribute().c_str());
}
{
if(!_locked) {
_attr_lock = true;
}
_attr_lock = false;
}
}
{
set_attr(_primitive_list.get_selected()->children, input->get_attribute(), input->get_as_attribute().c_str());
}
{
if(!_locked) {
_attr_lock = true;
_("Set filter primitive attribute"));
}
_attr_lock = false;
}
}
{
if(_settings_initialized != true) return;
if(!_locked) {
_attr_lock = true;
if(filter) {
}
else {
}
_attr_lock = false;
}
}
{
if(_attr_lock)
return;
//First Tab
_sw_infobox->show();
} else {
_sw_infobox->hide();
}
if(prim) {
//XML Tree being used directly here while it shouldn't be.
}
//Second Tab
if(filter) {
}
}
{
const bool use_k = SP_IS_FECOMPOSITE(prim) && SP_FECOMPOSITE(prim)->composite_operator == COMPOSITE_ARITHMETIC;
}
{
}
} // namespace Dialog
} // namespace UI
} // namespace Inkscape
/*
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 :