diff options
| author | Denis Declara <declara91@gmail.com> | 2012-03-20 10:09:49 +0000 |
|---|---|---|
| committer | Denis Declara <declara91@gmail.com> | 2012-03-20 10:09:49 +0000 |
| commit | 1cd9c8450500b945614a12a762e06c057ee85bbe (patch) | |
| tree | 9973553a223ef7d6c5f9d18c35766fb3e7296e57 /src | |
| parent | Fix deprecated Gtk::Widget flags (diff) | |
| parent | desktop cutting plotter dxf output. ignore orphaned clones (Bug 957086) (diff) | |
| download | inkscape-1cd9c8450500b945614a12a762e06c057ee85bbe.tar.gz inkscape-1cd9c8450500b945614a12a762e06c057ee85bbe.zip | |
Merged with trunk
(bzr r11073.1.1)
Diffstat (limited to 'src')
42 files changed, 2123 insertions, 1514 deletions
diff --git a/src/attribute-rel-css.cpp b/src/attribute-rel-css.cpp index b014aeb77..b45382b75 100644 --- a/src/attribute-rel-css.cpp +++ b/src/attribute-rel-css.cpp @@ -27,6 +27,8 @@ #include "preferences.h" SPAttributeRelCSS * SPAttributeRelCSS::instance = NULL; +bool SPAttributeRelCSS::foundFileProp = false; +bool SPAttributeRelCSS::foundFileDefault = false; /* * This function checks whether an element -> CSS property pair @@ -38,6 +40,9 @@ bool SPAttributeRelCSS::findIfValid(Glib::ustring property, Glib::ustring elemen SPAttributeRelCSS::instance = new SPAttributeRelCSS(); } + // Always valid if data file not found! + if( !foundFileProp ) return true; + // Strip of "svg:" from the element's name Glib::ustring temp = element; if ( temp.find("svg:") != std::string::npos ) { @@ -73,6 +78,9 @@ bool SPAttributeRelCSS::findIfDefault(Glib::ustring property, Glib::ustring valu SPAttributeRelCSS::instance = new SPAttributeRelCSS(); } + // Always false if data file not found! + if( !foundFileDefault ) return false; + if( instance->defaultValuesOfProps[property] == value) { return true; } else { @@ -89,6 +97,9 @@ bool SPAttributeRelCSS::findIfInherit(Glib::ustring property) SPAttributeRelCSS::instance = new SPAttributeRelCSS(); } + // Always false if data file not found! + if( !foundFileDefault ) return false; + return instance->inheritProps[property]; } @@ -101,6 +112,9 @@ bool SPAttributeRelCSS::findIfProperty(Glib::ustring property) SPAttributeRelCSS::instance = new SPAttributeRelCSS(); } + // Always true if data file not found! + if( !foundFileProp ) return true; + return ( instance->defaultValuesOfProps.find( property ) != instance->defaultValuesOfProps.end() ); } @@ -112,10 +126,8 @@ SPAttributeRelCSS::SPAttributeRelCSS() filepath += "/cssprops"; // Try and load data from filepath - if (!readDataFromFileIn(filepath, SPAttributeRelCSS::prop_element_pair)) { - // Set default preference for CSS property checking to ignore - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/options/svgoutput/incorrect_style_properties", 3); + if (readDataFromFileIn(filepath, SPAttributeRelCSS::prop_element_pair)) { + foundFileProp = true; } // Read data from standard path @@ -123,11 +135,10 @@ SPAttributeRelCSS::SPAttributeRelCSS() filepath += "/css_defaults"; // Try and load data from filepath - if (!readDataFromFileIn(filepath, SPAttributeRelCSS::prop_defValue_pair)) { - // Set default preference for CSS defaults checking to ignore - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/options/svgoutput/style_defaults", 3); + if (readDataFromFileIn(filepath, SPAttributeRelCSS::prop_defValue_pair)) { + foundFileDefault = true; } + } bool SPAttributeRelCSS::readDataFromFileIn(Glib::ustring fileName, storageType type) diff --git a/src/attribute-rel-css.h b/src/attribute-rel-css.h index b5077f8a0..5f3aaf253 100644 --- a/src/attribute-rel-css.h +++ b/src/attribute-rel-css.h @@ -43,6 +43,8 @@ private: prop_defValue_pair }; static SPAttributeRelCSS *instance; + static bool foundFileProp; + static bool foundFileDefault; hashList propertiesOfElements; // Data structure to store CSS property and default value pair diff --git a/src/attribute-rel-svg.cpp b/src/attribute-rel-svg.cpp index 3f5ce9395..80d924f80 100644 --- a/src/attribute-rel-svg.cpp +++ b/src/attribute-rel-svg.cpp @@ -26,6 +26,7 @@ #include "preferences.h" SPAttributeRelSVG * SPAttributeRelSVG::instance = NULL; +bool SPAttributeRelSVG::foundFile = false; /* * This functions checks whether an element -> attribute pair is allowed or not @@ -36,6 +37,9 @@ bool SPAttributeRelSVG::findIfValid(Glib::ustring attribute, Glib::ustring eleme SPAttributeRelSVG::instance = new SPAttributeRelSVG(); } + // Always valid if data file not found! + if( !foundFile ) return true; + // Strip of "svg:" from the element's name Glib::ustring temp = element; if ( temp.find("svg:") != std::string::npos ) { @@ -75,16 +79,14 @@ SPAttributeRelSVG::SPAttributeRelSVG() f.open(filepath.c_str(), std::ios::in); if (!f.is_open()) { - // Set the default preference of attribute checking to ignore - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/options/svgoutput/incorrect_attributes", 3); - // Display warning for file not open g_warning("Could not open the data file for XML attribute-element map construction: %s", filepath.c_str()); f.close(); return ; } + foundFile = true; + while (!f.eof()){ std::stringstream ss; std::string s; diff --git a/src/attribute-rel-svg.h b/src/attribute-rel-svg.h index f0ba314b6..74c6d3b60 100644 --- a/src/attribute-rel-svg.h +++ b/src/attribute-rel-svg.h @@ -31,6 +31,7 @@ private: private: static SPAttributeRelSVG *instance; + static bool foundFile; hashList attributesOfElements; }; diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index b6aea1b06..18f99cdcd 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -11,6 +11,8 @@ #include <cmath> #include <algorithm> +#include <deque> +#include <functional> #include "display/cairo-templates.h" #include "display/cairo-utils.h" #include "display/nr-filter-morphology.h" @@ -40,72 +42,118 @@ namespace { /* This performs one "half" of the morphology operation by calculating * the componentwise extreme in the specified axis with the given radius. - * Performing the operation one axis at a time gives us a MASSIVE performance boost - * at large morphology radii. Extreme of row extremes is equal to the extreme - * of components, so this doesn't change the result. */ -template <MorphologyOp OP, Geom::Dim2 axis> -struct Morphology : public SurfaceSynth { - Morphology(cairo_surface_t *in, double xradius) - : SurfaceSynth(in) - , _radius(round(xradius)) - {} - guint32 operator()(int x, int y) { - int start, end; - if (axis == Geom::X) { - start = std::max(0, x - _radius); - end = std::min(x + _radius + 1, _w); - } else { - start = std::max(0, y - _radius); - end = std::min(y + _radius + 1, _h); + * Extreme of row extremes is equal to the extreme of components, so this + * doesn't change the result. + * The algorithm is due to: Petr Dokládal, Eva Dokládalová (2011), "Computationally efficient, one-pass algorithm for morphological filters" + * TODO: Currently only the 1D algorithm is implemented, but it should not be too difficult (and at the very least more memory efficient) to implement the full 2D algorithm. + * One problem with the 2D algorithm is that it is harder to parallelize. + */ +template <typename Comparison, Geom::Dim2 axis, int BPP> +void morphologicalFilter1D(cairo_surface_t * const input, cairo_surface_t * const out, double radius) { + Comparison comp; + + int w = cairo_image_surface_get_width(out); + int h = cairo_image_surface_get_height(out); + if (axis == Geom::Y) std::swap(w,h); + + int stridein = cairo_image_surface_get_stride(input); + int strideout = cairo_image_surface_get_stride(out); + + unsigned char *in_data = cairo_image_surface_get_data(input); + unsigned char *out_data = cairo_image_surface_get_data(out); + + int ri = round(radius); // TODO: Support fractional radii? + int wi = 2*ri+1; + + #if HAVE_OPENMP + int limit = w * h; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int numOfThreads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); + #pragma omp parallel for if(limit > OPENMP_THRESHOLD) num_threads(numOfThreads) + #endif // HAVE_OPENMP + for (int i = 0; i < h; ++i) { + // TODO: Store position and value in one 32 bit integer? 24 bits should be enough for a position, it would be quite strange to have an image with a width/height of more than 16 million(!). + std::deque< std::pair<int,unsigned char> > vals[BPP]; // In my tests it was actually slightly faster to allocate it here than allocate it once for all threads and retrieving the correct set based on the thread id. + + // Initialize with transparent black + for(int p = 0; p < BPP; ++p) { + vals[p].push_back(std::pair<int,unsigned char>(-1,0)); // TODO: Only do this when performing an erosion? } - guint32 ao = (OP == DILATE ? 0 : 255); - guint32 ro = (OP == DILATE ? 0 : 255); - guint32 go = (OP == DILATE ? 0 : 255); - guint32 bo = (OP == DILATE ? 0 : 255); - - if (_alpha) { - ao = (OP == DILATE ? 0 : 0xff000000); - for (int i = start; i < end; ++i) { - guint32 px = (axis == Geom::X ? pixelAt(i, y) : pixelAt(x, i)); - if (OP == DILATE) { - if (px > ao) ao = px; - } else { - if (px < ao) ao = px; + // Process "row" + unsigned char *in_p = in_data + i * (axis == Geom::X ? stridein : BPP); + unsigned char *out_p = out_data + i * (axis == Geom::X ? strideout : BPP); + /* This is the "short but slow" version, which might be easier to follow, the longer but faster version follows. + for (int j = 0; j < w+ri; ++j) { + for(int p = 0; p < BPP; ++p) { // Iterate over channels + // Push new value onto FIFO, erasing any previous values that are "useless" (see paper) or out-of-range + if (!vals[p].empty() && vals[p].front().first+wi <= j) vals[p].pop_front(); // out-of-range + if (j < w) { + while(!vals[p].empty() && !comp(vals[p].back().second, *in_p)) vals[p].pop_back(); // useless + vals[p].push_back(std::make_pair(j, *in_p)); + ++in_p; + } else if (j == w) { // Transparent black beyond the image. TODO: Only do this when performing an erosion? + while(!vals[p].empty() && !comp(vals[p].back().second, 0)) vals[p].pop_back(); + vals[p].push_back(std::make_pair(j, 0)); } - } - return ao; - } else { - for (int i = start; i < end; ++i) { - guint32 px = (axis == Geom::X ? pixelAt(i, y) : pixelAt(x, i)); - EXTRACT_ARGB32(px, a,r,g,b); - - // this will be compiled to conditional moves; - // the operator comparison will be evaluated at compile time. - // therefore there will be no branching in this loop - if (OP == DILATE) { - if (a > ao) ao = a; - if (r > ro) ro = r; - if (g > go) go = g; - if (b > bo) bo = b; - } else { - if (a < ao) ao = a; - if (r < ro) ro = r; - if (g < go) go = g; - if (b < bo) bo = b; + // Set output + if (j >= ri) { + *out_p = vals[p].front().second; + ++out_p; } - - // TODO: verify whether this check gives any speedup. - if (OP == ERODE && a == 0) break; } - - ASSEMBLE_ARGB32(pxout, ao,ro,go,bo) - return pxout; + if (axis == Geom::Y && j < w ) in_p += stridein - BPP; + if (axis == Geom::Y && j >= ri) out_p += strideout - BPP; + }*/ + for (int j = 0; j < std::min(ri,w); ++j) { + for(int p = 0; p < BPP; ++p) { // Iterate over channels + // Push new value onto FIFO, erasing any previous values that are "useless" (see paper) or out-of-range + if (!vals[p].empty() && vals[p].front().first <= j) vals[p].pop_front(); // out-of-range + while(!vals[p].empty() && !comp(vals[p].back().second, *in_p)) vals[p].pop_back(); // useless + vals[p].push_back(std::make_pair(j+wi, *in_p)); + ++in_p; + } + if (axis == Geom::Y) in_p += stridein - BPP; + } + // We have now done all preparatory work. + // If w<=ri, then the following loop does nothing (which is as it should). + for (int j = ri; j < w; ++j) { + for(int p = 0; p < BPP; ++p) { // Iterate over channels + // Push new value onto FIFO, erasing any previous values that are "useless" (see paper) or out-of-range + if (!vals[p].empty() && vals[p].front().first <= j) vals[p].pop_front(); // out-of-range + while(!vals[p].empty() && !comp(vals[p].back().second, *in_p)) vals[p].pop_back(); // useless + vals[p].push_back(std::make_pair(j+wi, *in_p)); + ++in_p; + // Set output + *out_p = vals[p].front().second; + ++out_p; + } + if (axis == Geom::Y) { + in_p += stridein - BPP; + out_p += strideout - BPP; + } + } + // We have now done all work which involves both input and output. + // The following loop makes sure that the border is handled correctly. + for(int p = 0; p < BPP; ++p) { // Iterate over channels + while(!vals[p].empty() && !comp(vals[p].back().second, 0)) vals[p].pop_back(); + vals[p].push_back(std::make_pair(w+wi, 0)); + } + // Now we just have to finish the output. + for (int j = std::max(w,ri); j < w+ri; ++j) { + for(int p = 0; p < BPP; ++p) { // Iterate over channels + // Remove out-of-range values + if (!vals[p].empty() && vals[p].front().first <= j) vals[p].pop_front(); // out-of-range + // Set output + *out_p = vals[p].front().second; + ++out_p; + } + if (axis == Geom::Y) out_p += strideout - BPP; } } -private: - int _radius; -}; + + cairo_surface_mark_dirty(out); +} } // end anonymous namespace @@ -122,23 +170,40 @@ void FilterMorphology::render_cairo(FilterSlot &slot) } Geom::Affine p2pb = slot.get_units().get_matrix_primitiveunits2pb(); - double xr = xradius * p2pb.expansionX(); - double yr = yradius * p2pb.expansionY(); + double xr = fabs(xradius * p2pb.expansionX()); + double yr = fabs(yradius * p2pb.expansionY()); + int bpp = cairo_image_surface_get_format(input) == CAIRO_FORMAT_A8 ? 1 : 4; cairo_surface_t *interm = ink_cairo_surface_create_identical(input); if (Operator == MORPHOLOGY_OPERATOR_DILATE) { - ink_cairo_surface_synthesize(interm, Morphology<DILATE, Geom::X>(input, xr)); + if (bpp == 1) { + morphologicalFilter1D< std::greater<unsigned char>, Geom::X, 1 >(input, interm, xr); + } else { + morphologicalFilter1D< std::greater<unsigned char>, Geom::X, 4 >(input, interm, xr); + } } else { - ink_cairo_surface_synthesize(interm, Morphology<ERODE, Geom::X>(input, xr)); + if (bpp == 1) { + morphologicalFilter1D< std::less<unsigned char>, Geom::X, 1 >(input, interm, xr); + } else { + morphologicalFilter1D< std::less<unsigned char>, Geom::X, 4 >(input, interm, xr); + } } - cairo_surface_t *out = ink_cairo_surface_create_identical(input); + cairo_surface_t *out = ink_cairo_surface_create_identical(interm); if (Operator == MORPHOLOGY_OPERATOR_DILATE) { - ink_cairo_surface_synthesize(out, Morphology<DILATE, Geom::Y>(interm, yr)); + if (bpp == 1) { + morphologicalFilter1D< std::greater<unsigned char>, Geom::Y, 1 >(interm, out, yr); + } else { + morphologicalFilter1D< std::greater<unsigned char>, Geom::Y, 4 >(interm, out, yr); + } } else { - ink_cairo_surface_synthesize(out, Morphology<ERODE, Geom::Y>(interm, yr)); + if (bpp == 1) { + morphologicalFilter1D< std::less<unsigned char>, Geom::Y, 1 >(interm, out, yr); + } else { + morphologicalFilter1D< std::less<unsigned char>, Geom::Y, 4 >(interm, out, yr); + } } cairo_surface_destroy(interm); diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index deb354d00..4519befcf 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -8,6 +8,7 @@ #include "extension/input.h" #include "extension/system.h" #include "gdkpixbuf-input.h" +#include "preferences.h" #include "selection-chemistry.h" #include "sp-image.h" #include "document-undo.h" @@ -33,7 +34,20 @@ static std::set<Glib::ustring> create_lossy_set() SPDocument * GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) { - bool embed = (strcmp(mod->get_param_optiongroup("link"), "embed") == 0); + bool embed = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring attr = prefs->getString("/dialogs/import/link"); + if (strcmp(attr.c_str(), "embed") == 0) { + embed = true; + } else if (strcmp(attr.c_str(), "link") == 0) { + embed = false; + } else { + embed = (strcmp(mod->get_param_optiongroup("link"), "embed") == 0); + if (mod->get_param_bool("ask")) { + prefs->setString("/dialogs/import/link", mod->get_param_optiongroup("link")); + mod->set_param_bool("ask", false); + } + } SPDocument *doc = NULL; GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL ); @@ -146,22 +160,24 @@ GdkpixbufInput::init(void) if (strcmp(extensions[i], "svg.gz") == 0) { continue; } - gchar *caption = g_strdup_printf(_("%s GDK pixbuf Input"), name); + gchar *caption = g_strdup_printf(_("%s bitmap image import"), name); + gchar *xmlString = g_strdup_printf( "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>%s</name>\n" - "<id>org.inkscape.input.gdkpixbuf.%s</id>\n" - "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Link or embed image:") "' >\n" - "<_option value='embed'>" N_("Embed") "</_option>\n" - "<_option value='link'>" N_("Link") "</_option>\n" - "</param>\n" - "<_param name='help' type='description'>" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "</_param>\n" - "<input>\n" - "<extension>.%s</extension>\n" - "<mimetype>%s</mimetype>\n" - "<filetypename>%s (*.%s)</filetypename>\n" - "<filetypetooltip>%s</filetypetooltip>\n" - "</input>\n" + "<name>%s</name>\n" + "<id>org.inkscape.input.gdkpixbuf.%s</id>\n" + "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Link or embed image:") "' >\n" + "<_option value='embed' >" N_("Embed") "</_option>\n" + "<_option value='link' >" N_("Link") "</_option>\n" + "</param>\n" + "<_param name='help' type='description'>" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "</_param>\n" + "<param name=\"ask\" _gui-description='" N_("Hide the dialog next time and always apply the same action.") "' gui-text=\"" N_("Don't ask again") "\" type=\"boolean\" >false</param>\n" + "<input>\n" + "<extension>.%s</extension>\n" + "<mimetype>%s</mimetype>\n" + "<filetypename>%s (*.%s)</filetypename>\n" + "<filetypetooltip>%s</filetypetooltip>\n" + "</input>\n" "</inkscape-extension>", caption, extensions[i], diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index 1c21fbca3..3b19f925e 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -1619,6 +1619,7 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) GfxShading *shading = 0; GfxPath *savedPath = NULL; double xMin, yMin, xMax, yMax; + double xTemp, yTemp; double gradientTransform[6]; double *matrix = NULL; GBool savedState = gFalse; @@ -1668,6 +1669,16 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) // clip to bbox if (shading->getHasBBox()) { shading->getBBox(&xMin, &yMin, &xMax, &yMax); + if (matrix != NULL) { + xTemp = matrix[0]*xMin + matrix[2]*yMin + matrix[4]; + yTemp = matrix[1]*xMin + matrix[3]*yMin + matrix[5]; + xMin = xTemp; + yMin = yTemp; + xTemp = matrix[0]*xMax + matrix[2]*yMax + matrix[4]; + yTemp = matrix[1]*xMax + matrix[3]*yMax + matrix[5]; + xMax = xTemp; + yMax = yTemp; + } state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp index c5304106c..f15d56f0d 100644 --- a/src/extension/param/string.cpp +++ b/src/extension/param/string.cpp @@ -97,7 +97,16 @@ ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar defaultval = paramval.data(); } if (defaultval != NULL) { - _value = g_strdup(defaultval); + char const * chname = xml->name(); + if (!strcmp(chname, INKSCAPE_EXTENSION_NS "_param")) { + if (xml->attribute("msgctxt") != NULL) { + _value = g_strdup(g_dpgettext2(NULL, xml->attribute("msgctxt"), defaultval)); + } else { + _value = g_strdup(_(defaultval)); + } + } else { + _value = g_strdup(defaultval); + } } _max_length = 0; diff --git a/src/extension/system.cpp b/src/extension/system.cpp index b3e9beebf..ebad0c050 100644 --- a/src/extension/system.cpp +++ b/src/extension/system.cpp @@ -88,6 +88,19 @@ SPDocument *open(Extension *key, gchar const *filename) throw Input::no_extension_found(); } + // Hide pixbuf extensions depending on user preferences. + //g_warning("Extension: %s", imod->get_id()); + + bool show = true; + if (strlen(imod->get_id()) > 27) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring attr = prefs->getString("/dialogs/import/link"); + Glib::ustring id = Glib::ustring(imod->get_id(), 28); + if (strcmp(attr.c_str(), "ask") != 0 and strcmp(id.c_str(), "org.inkscape.input.gdkpixbuf") == 0) { + show = false; + imod->set_gui(false); + } + } imod->set_state(Extension::STATE_LOADED); if (!imod->loaded()) { @@ -112,6 +125,9 @@ SPDocument *open(Extension *key, gchar const *filename) } doc->setUri(filename); + if (!show) { + imod->set_gui(true); + } return doc; } diff --git a/src/file.cpp b/src/file.cpp index 8dac0f575..dbf8fc7d4 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1148,6 +1148,9 @@ sp_file_import(Gtk::Window &parentWindow) return; } + typedef std::vector<Glib::ustring> pathnames; + pathnames flist(importDialogInstance->getFilenames()); + // Get file name and extension type Glib::ustring fileName = importDialogInstance->getFilename(); Inkscape::Extension::Extension *selection = importDialogInstance->getSelectionType(); @@ -1155,16 +1158,39 @@ sp_file_import(Gtk::Window &parentWindow) delete importDialogInstance; importDialogInstance = NULL; - if (fileName.size() > 0) { + //# Iterate through filenames if more than 1 + if (flist.size() > 1) + { + for (unsigned int i = 0; i < flist.size(); i++) + { + fileName = flist[i]; + + Glib::ustring newFileName = Glib::filename_to_utf8(fileName); + if (!newFileName.empty()) + fileName = newFileName; + else + g_warning("ERROR CONVERTING IMPORT FILENAME TO UTF-8"); + +#ifdef INK_DUMP_FILENAME_CONV + g_message("Importing File %s\n", fileName.c_str()); +#endif + file_import(doc, fileName, selection); + } + + return; + } + + + if (!fileName.empty()) { Glib::ustring newFileName = Glib::filename_to_utf8(fileName); - if ( newFileName.size() > 0) + if (!newFileName.empty()) fileName = newFileName; else - g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" ); + g_warning("ERROR CONVERTING IMPORT FILENAME TO UTF-8"); - import_path = Glib::path_get_dirname (fileName); + import_path = Glib::path_get_dirname(fileName); import_path.append(G_DIR_SEPARATOR_S); prefs->setString("/dialogs/import/path", import_path); diff --git a/src/helper/unit-menu.cpp b/src/helper/unit-menu.cpp index 2757536a2..ce64cabf4 100644 --- a/src/helper/unit-menu.cpp +++ b/src/helper/unit-menu.cpp @@ -26,7 +26,9 @@ struct SPUnitSelector { GtkHBox box; - GtkWidget *menu; + GtkWidget *combo_box; + GtkListStore *store; + guint bases; GSList *units; @@ -40,6 +42,8 @@ struct SPUnitSelector { GSList *adjustments; }; +enum {COMBO_COL_LABEL=0, COMBO_COL_UNIT}; + struct SPUnitSelectorClass { GtkHBoxClass parent_class; @@ -101,10 +105,21 @@ sp_unit_selector_init(SPUnitSelector *us) us->abbr = FALSE; us->plural = TRUE; - us->menu = gtk_option_menu_new(); - - gtk_widget_show(us->menu); - gtk_box_pack_start(GTK_BOX(us), us->menu, TRUE, TRUE, 0); + /** + * Create a combo_box and store with 2 columns, + * a label and a pointer to a SPUnit + */ + us->store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); + us->combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (us->store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "scale", 0.8, "scale-set", TRUE, NULL); + gtk_cell_renderer_set_padding (renderer, 2, 0); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (us->combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (us->combo_box), renderer, "text", COMBO_COL_LABEL, NULL); + + gtk_widget_show (us->combo_box); + gtk_box_pack_start (GTK_BOX(us), us->combo_box, TRUE, TRUE, 0); } static void @@ -112,8 +127,8 @@ sp_unit_selector_finalize(GObject *object) { SPUnitSelector *selector = SP_UNIT_SELECTOR(object); - if (selector->menu) { - selector->menu = NULL; + if (selector->combo_box) { + selector->combo_box = NULL; } while (selector->adjustments) { @@ -143,7 +158,7 @@ sp_unit_selector_new(guint bases) void sp_unit_selector_setsize(GtkWidget *us, guint w, guint h) { - gtk_widget_set_size_request(((SPUnitSelector *) us)->menu, w, h); + gtk_widget_set_size_request(((SPUnitSelector *) us)->combo_box, w, h); } SPUnit const * @@ -155,10 +170,18 @@ sp_unit_selector_get_unit(SPUnitSelector const *us) return us->unit; } + static void -spus_unit_activate(GtkWidget *widget, SPUnitSelector *us) +on_combo_box_changed (GtkComboBox *widget, SPUnitSelector *us) { - SPUnit const *unit = (SPUnit const *) g_object_get_data(G_OBJECT(widget), "unit"); + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (widget, &iter)) { + return; + } + + SPUnit const *unit = NULL; + gtk_tree_model_get ((GtkTreeModel *)us->store, &iter, COMBO_COL_UNIT, &unit, -1); + g_return_if_fail(unit != NULL); #ifdef UNIT_SELECTOR_VERBOSE @@ -205,18 +228,16 @@ spus_unit_activate(GtkWidget *widget, SPUnitSelector *us) } us->update = FALSE; + } static void spus_rebuild_menu(SPUnitSelector *us) { - if (GTK_OPTION_MENU(us->menu)->menu) { - gtk_option_menu_remove_menu(GTK_OPTION_MENU(us->menu)); - } - GtkWidget *m = gtk_menu_new(); + gtk_list_store_clear(us->store); - gtk_widget_show(m); + GtkTreeIter iter; gint pos = 0; gint p = 0; @@ -225,23 +246,18 @@ spus_rebuild_menu(SPUnitSelector *us) // use only abbreviations in the menu // i = gtk_menu_item_new_with_label((us->abbr) ? (us->plural) ? u->abbr_plural : u->abbr : (us->plural) ? u->plural : u->name); - GtkWidget *i = gtk_menu_item_new_with_label( u->abbr ); - - g_object_set_data(G_OBJECT(i), "unit", (gpointer) u); - g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(spus_unit_activate), us); + gtk_list_store_append (us->store, &iter); + gtk_list_store_set (us->store, &iter, COMBO_COL_LABEL, u->abbr, COMBO_COL_UNIT, (gpointer) u, -1); - sp_set_font_size_smaller (i); - - gtk_widget_show(i); + if (u == us->unit) { + pos = p; + } - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - if (u == us->unit) pos = p; p += 1; } - gtk_option_menu_set_menu(GTK_OPTION_MENU(us->menu), m); - - gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos); + gtk_combo_box_set_active(GTK_COMBO_BOX(us->combo_box), pos); + g_signal_connect (G_OBJECT (us->combo_box), "changed", G_CALLBACK (on_combo_box_changed), us); } void @@ -287,7 +303,7 @@ sp_unit_selector_set_unit(SPUnitSelector *us, SPUnit const *unit) gint const pos = g_slist_index(us->units, (gpointer) unit); g_return_if_fail(pos >= 0); - gtk_option_menu_set_history(GTK_OPTION_MENU(us->menu), pos); + gtk_combo_box_set_active(GTK_COMBO_BOX(us->combo_box), pos); SPUnit const *old = us->unit; us->unit = unit; diff --git a/src/inkscape.rc b/src/inkscape.rc index e3e79ffe5..efa360c8d 100644 --- a/src/inkscape.rc +++ b/src/inkscape.rc @@ -15,7 +15,7 @@ BEGIN VALUE "FileDescription", "Inkscape" VALUE "FileVersion", "0.48+devel" VALUE "InternalName", "Inkscape" - VALUE "LegalCopyright", "© 2011 Inkscape" + VALUE "LegalCopyright", "© 2012 Inkscape" VALUE "ProductName", "Inkscape" VALUE "ProductVersion", "0.48+devel" END diff --git a/src/inkview.rc b/src/inkview.rc index 83bb89ba4..f1fa92247 100644 --- a/src/inkview.rc +++ b/src/inkview.rc @@ -15,7 +15,7 @@ BEGIN VALUE "FileDescription", "Inkview" VALUE "FileVersion", "0.48+devel" VALUE "InternalName", "Inkview" - VALUE "LegalCopyright", "© 2010 Inkscape" + VALUE "LegalCopyright", "© 2012 Inkscape" VALUE "ProductName", "Inkview" VALUE "ProductVersion", "0.48+devel" END diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index b4f1e12cc..18b7150f5 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -196,7 +196,7 @@ static char const preferences_skeleton[] = " <group id=\"save_as\" default=\"\" append_extension=\"1\" enable_preview=\"1\" path=\"\" use_current_dir=\"1\"/>\n" " <group id=\"save_copy\" default=\"\" append_extension=\"1\" enable_preview=\"1\" path=\"\"/>\n" " <group id=\"open\" enable_preview=\"1\" path=\"\"/>\n" -" <group id=\"import\" enable_preview=\"1\" path=\"\"/>\n" +" <group id=\"import\" enable_preview=\"1\" path=\"\" link=\"ask\"/>\n" " <group id=\"debug\" redirect=\"0\"/>\n" " <group id=\"clonetiler\" />\n" " <group id=\"gridtiler\" />\n" diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 9b39dab10..d0fba0de5 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -376,6 +376,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) std::vector<const gchar *> new_ids; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); + const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); while (reprs) { Inkscape::XML::Node *old_repr = (Inkscape::XML::Node *) reprs->data; @@ -391,6 +392,13 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) add_ids_recursive(new_ids, new_obj); } + if (fork_livepatheffects) { + SPObject *new_obj = doc->getObjectByRepr(copy); + if (new_obj && SP_IS_LPE_ITEM(new_obj)) { + sp_lpe_item_fork_path_effects_if_necessary(SP_LPE_ITEM(new_obj), 1); + } + } + newsel = g_slist_prepend(newsel, copy); reprs = g_slist_remove(reprs, reprs->data); Inkscape::GC::release(copy); diff --git a/src/sp-object.cpp b/src/sp-object.cpp index efa11b4fd..892c89a15 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -192,14 +192,14 @@ void SPObject::sp_object_finalize(GObject *object) spobject->_successor = NULL; } - if (((GObjectClass *) (SPObjectClass::static_parent_class))->finalize) { - (* ((GObjectClass *) (SPObjectClass::static_parent_class))->finalize)(object); - } - spobject->_release_signal.~signal(); spobject->_modified_signal.~signal(); spobject->_delete_signal.~signal(); spobject->_position_changed_signal.~signal(); + + if (((GObjectClass *) (SPObjectClass::static_parent_class))->finalize) { + (* ((GObjectClass *) (SPObjectClass::static_parent_class))->finalize)(object); + } } namespace { diff --git a/src/text-context.cpp b/src/text-context.cpp index f1becb58d..724c40aa8 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -705,6 +705,17 @@ static gint sp_text_context_root_handler(SPEventContext *const event_context, Gd // artificially here, for the text object does not exist yet: double cursor_height = sp_desktop_get_font_size_tool(desktop); sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), p1, p1 + Geom::Point(0, cursor_height)); + if (tc->imc) { + GdkRectangle im_cursor; + Geom::Point const top_left = SP_EVENT_CONTEXT(tc)->desktop->get_display_area().corner(3); + Geom::Point const cursor_size(0, cursor_height); + Geom::Point const im_position = SP_EVENT_CONTEXT(tc)->desktop->d2w(p1 + cursor_size - top_left); + im_cursor.x = (int) floor(im_position[Geom::X]); + im_cursor.y = (int) floor(im_position[Geom::Y]); + im_cursor.width = 0; + im_cursor.height = (int) -floor(SP_EVENT_CONTEXT(tc)->desktop->d2w(cursor_size)[Geom::Y]); + gtk_im_context_set_cursor_location(tc->imc, &im_cursor); + } event_context->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Type text; <b>Enter</b> to start new line.")); // FIXME:: this is a copy of a string from _update_cursor below, do not desync event_context->within_tolerance = false; @@ -1572,8 +1583,6 @@ static void sp_text_context_validate_cursor_iterators(SPTextContext *tc) static void sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see) { - GdkRectangle im_cursor = { 0, 0, 1, 1 }; - // due to interruptible display, tc may already be destroyed during a display update before // the cursor update (can't do both atomically, alas) if (!tc->desktop) return; @@ -1598,10 +1607,17 @@ static void sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see sp_ctrlline_set_coords(SP_CTRLLINE(tc->cursor), d0, d1); /* fixme: ... need another transformation to get canvas widget coordinate space? */ - im_cursor.x = (int) floor(d0[Geom::X]); - im_cursor.y = (int) floor(d0[Geom::Y]); - im_cursor.width = (int) floor(d1[Geom::X]) - im_cursor.x; - im_cursor.height = (int) floor(d1[Geom::Y]) - im_cursor.y; + if (tc->imc) { + GdkRectangle im_cursor = { 0, 0, 1, 1 }; + Geom::Point const top_left = SP_EVENT_CONTEXT(tc)->desktop->get_display_area().corner(3); + Geom::Point const im_d0 = SP_EVENT_CONTEXT(tc)->desktop->d2w(d0 - top_left); + Geom::Point const im_d1 = SP_EVENT_CONTEXT(tc)->desktop->d2w(d1 - top_left); + im_cursor.x = (int) floor(im_d0[Geom::X]); + im_cursor.y = (int) floor(im_d1[Geom::Y]); + im_cursor.width = (int) floor(im_d1[Geom::X]) - im_cursor.x; + im_cursor.height = (int) floor(im_d0[Geom::Y]) - im_cursor.y; + gtk_im_context_set_cursor_location(tc->imc, &im_cursor); + } tc->show = TRUE; tc->phase = 1; @@ -1643,9 +1659,6 @@ static void sp_text_context_update_cursor(SPTextContext *tc, bool scroll_to_see } } - if (tc->imc) { - gtk_im_context_set_cursor_location(tc->imc, &im_cursor); - } SP_EVENT_CONTEXT(tc)->desktop->emitToolSubselectionChanged((gpointer)tc); } diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index e32f59fa3..b9d6e0c6b 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -82,6 +82,7 @@ #include "sp-namedview.h" #include "snap.h" #include "persp3d.h" +#include "preferences.h" /// Made up mimetype to represent Gdk::Pixbuf clipboard contents. #define CLIPBOARD_GDK_PIXBUF_TARGET "image/x-gdk-pixbuf" @@ -926,16 +927,16 @@ bool ClipboardManagerImpl::_pasteImage(SPDocument *doc) ++i; } Inkscape::Extension::Extension *png = *i; - bool save = (strcmp(png->get_param_optiongroup("link"), "embed") == 0); - png->set_param_optiongroup("link", "embed"); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring attr = prefs->getString("/dialogs/import/link"); + prefs->setString("/dialogs/import/link", "embed"); png->set_gui(false); gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-clipboard-import", NULL ); img->save(filename, "png"); file_import(doc, filename, png); g_free(filename); - - png->set_param_optiongroup("link", save ? "embed" : "link"); + prefs->setString("/dialogs/import/link", attr); png->set_gui(true); return true; diff --git a/src/ui/context-menu.cpp b/src/ui/context-menu.cpp index 06fc6c4ef..4bb8b4803 100644 --- a/src/ui/context-menu.cpp +++ b/src/ui/context-menu.cpp @@ -1,605 +1,675 @@ -/* - * Unser-interface related object extension - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * Jon A. Cruz <jon@joncruz.org> - * Abhishek Sharma - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui/dialog/dialog-manager.h" -#include "context-menu.h" -#include "../xml/repr.h" -#include "desktop.h" -#include "document.h" -#include "document-undo.h" -#include "inkscape.h" -#include "message-stack.h" -#include "preferences.h" -#include "verbs.h" - -using Inkscape::DocumentUndo; - -static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu); - -/* Append object-specific part to context menu */ - -void sp_object_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu) -{ - GObjectClass *klass; - klass = G_OBJECT_GET_CLASS(object); - while (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_OBJECT)) { - GType type; - type = G_TYPE_FROM_CLASS(klass); - sp_object_type_menu(type, object, desktop, menu); - klass = (GObjectClass*)g_type_class_peek_parent(klass); - } -} - -/* Implementation */ - -#include <gtk/gtk.h> -#include <glibmm/i18n.h> - -#include "selection.h" -#include "selection-chemistry.h" -#include "sp-anchor.h" -#include "sp-clippath.h" -#include "sp-image.h" -#include "sp-mask.h" -#include "sp-path.h" -#include "sp-text.h" -#include "desktop-handles.h" -#include "ui/dialog/object-attributes.h" -#include "ui/dialog/object-properties.h" -#include "ui/dialog/spellcheck.h" - - -static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); -static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); -static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); -static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); -static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); -static void sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu); - -static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu) -{ - static GHashTable *t2m = NULL; - void (* handler)(SPObject *object, SPDesktop *desktop, GtkMenu *menu); - if (!t2m) { - t2m = g_hash_table_new(NULL, NULL); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ITEM), (void*)sp_item_menu); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_GROUP), (void*)sp_group_menu); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ANCHOR), (void*)sp_anchor_menu); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_IMAGE), (void*)sp_image_menu); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_SHAPE), (void*)sp_shape_menu); - g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_TEXT), (void*)sp_text_menu); - } - handler = (void (*)(SPObject*, SPDesktop*, GtkMenu*))g_hash_table_lookup(t2m, GUINT_TO_POINTER(type)); - if (handler) handler(object, desktop, menu); -} - -/* SPItem */ - -static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item); -static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item); -static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item); -static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item); -static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item); -static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item); -static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item); - -/* Generate context menu item section */ -static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) -{ - SPItem *item; - GtkWidget *w; - - item = (SPItem *) object; - - /* Item dialog */ - w = gtk_menu_item_new_with_mnemonic(_("_Object Properties...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_properties), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Separator */ - w = gtk_menu_item_new(); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Select item */ - w = gtk_menu_item_new_with_mnemonic(_("_Select This")); - if (sp_desktop_selection(desktop)->includes(item)) { - gtk_widget_set_sensitive(w, FALSE); - } else { - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_select_this), item); - } - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Create link */ - w = gtk_menu_item_new_with_mnemonic(_("_Create Link")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_create_link), item); - gtk_widget_set_sensitive(w, !SP_IS_ANCHOR(item)); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Set mask */ - w = gtk_menu_item_new_with_mnemonic(_("Set Mask")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_set_mask), item); - if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) { - gtk_widget_set_sensitive(w, FALSE); - } else { - gtk_widget_set_sensitive(w, TRUE); - } - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Release mask */ - w = gtk_menu_item_new_with_mnemonic(_("Release Mask")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_release_mask), item); - if (item && item->mask_ref && item->mask_ref->getObject()) { - gtk_widget_set_sensitive(w, TRUE); - } else { - gtk_widget_set_sensitive(w, FALSE); - } - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Set Clip */ - w = gtk_menu_item_new_with_mnemonic(_("Set _Clip")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_set_clip), item); - if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) { - gtk_widget_set_sensitive(w, FALSE); - } else { - gtk_widget_set_sensitive(w, TRUE); - } - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Release Clip */ - w = gtk_menu_item_new_with_mnemonic(_("Release C_lip")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_release_clip), item); - if (item && item->clip_ref && item->clip_ref->getObject()) { - gtk_widget_set_sensitive(w, TRUE); - } else { - gtk_widget_set_sensitive(w, FALSE); - } - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - -} - -static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_desktop_selection(desktop)->set(item); - - // sp_item_dialog(); - desktop->_dlg_mgr->showDialog("ObjectProperties"); -} - - -static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_selection_set_mask(desktop, false, false); -} - - -static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_selection_unset_mask(desktop, false); -} - - -static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_selection_set_mask(desktop, true, false); -} - - -static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_selection_unset_mask(desktop, true); -} - - -static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - sp_desktop_selection(desktop)->set(item); -} - -static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item) -{ - g_assert(SP_IS_ITEM(item)); - g_assert(!SP_IS_ANCHOR(item)); - - SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("svg:a"); - item->parent->getRepr()->addChild(repr, item->getRepr()); - SPObject *object = item->document->getObjectByRepr(repr); - g_return_if_fail(SP_IS_ANCHOR(object)); - - const char *id = item->getRepr()->attribute("id"); - Inkscape::XML::Node *child = item->getRepr()->duplicate(xml_doc); - item->deleteObject(false); - repr->addChild(child, NULL); - child->setAttribute("id", id); - - Inkscape::GC::release(repr); - Inkscape::GC::release(child); - - DocumentUndo::done(object->document, SP_VERB_NONE, - _("Create link")); - - sp_desktop_selection(desktop)->set(SP_ITEM(object)); - desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -/* SPGroup */ - -static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group); - -static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu) -{ - SPItem *item=SP_ITEM(object); - GtkWidget *w; - - /* "Ungroup" */ - w = gtk_menu_item_new_with_mnemonic(_("_Ungroup")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_group_ungroup_activate), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), w); -} - -static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group) -{ - SPDesktop *desktop; - GSList *children; - - g_assert(SP_IS_GROUP(group)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - children = NULL; - sp_item_group_ungroup(group, &children); - - sp_desktop_selection(desktop)->setList(children); - g_slist_free(children); -} - -/* SPAnchor */ - -static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor); -static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor); -static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor); - -static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) -{ - SPItem *item; - GtkWidget *w; - - item = (SPItem *) object; - - /* Link dialog */ - w = gtk_menu_item_new_with_mnemonic(_("Link _Properties...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_properties), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Select item */ - w = gtk_menu_item_new_with_mnemonic(_("_Follow Link")); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_follow), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - /* Reset transformations */ - w = gtk_menu_item_new_with_mnemonic(_("_Remove Link")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_remove), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); -} - -static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor */*anchor*/) -{ - SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -static void sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor) -{ - g_return_if_fail(anchor != NULL); - g_return_if_fail(SP_IS_ANCHOR(anchor)); - - /* shell out to an external browser here */ -} - -static void sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor) -{ - GSList *children; - - g_return_if_fail(anchor != NULL); - g_return_if_fail(SP_IS_ANCHOR(anchor)); - - children = NULL; - sp_item_group_ungroup(SP_GROUP(anchor), &children); - - g_slist_free(children); -} - -/* Image */ - -static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor); -static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor); - -static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) -{ - SPItem *item = SP_ITEM(object); - GtkWidget *w; - - /* Link dialog */ - w = gtk_menu_item_new_with_mnemonic(_("Image _Properties...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_properties), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - - w = gtk_menu_item_new_with_mnemonic(_("Edit Externally...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_edit), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - Inkscape::XML::Node *ir = object->getRepr(); - const gchar *href = ir->attribute("xlink:href"); - if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { - gtk_widget_set_sensitive( w, FALSE ); - } -} - -static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor */*anchor*/) -{ - SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -static gchar* getImageEditorName() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gchar* value = 0; - Glib::ustring choices = prefs->getString("/options/bitmapeditor/value"); - if (!choices.empty()) { - value = g_strdup(choices.c_str()); - } - if (!value) { - value = g_strdup("gimp"); - } - return value; -} - -static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor) -{ - SPObject* obj = anchor; - Inkscape::XML::Node *ir = obj->getRepr(); - const gchar *href = ir->attribute("xlink:href"); - - GError* errThing = 0; - Glib::ustring cmdline = getImageEditorName(); - Glib::ustring name; - Glib::ustring fullname; - -#ifdef WIN32 - // g_spawn_command_line_sync parsing is done according to Unix shell rules, - // not Windows command interpreter rules. Thus we need to enclose the - // executable path with sigle quotes. - int index = cmdline.find(".exe"); - if ( index < 0 ) index = cmdline.find(".bat"); - if ( index < 0 ) index = cmdline.find(".com"); - if ( index >= 0 ) { - Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str(); - Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str(); - editorBin.insert(0, "'"); - editorBin.append("'"); - cmdline = editorBin; - cmdline.append(args); - } else { - // Enclose the whole command line if no executable path can be extracted. - cmdline.insert(0, "'"); - cmdline.append("'"); - } -#endif - - if (strncmp (href,"file:",5) == 0) { - // URI to filename conversion - name = g_filename_from_uri(href, NULL, NULL); - } else { - name.append(href); - } - - - if (Glib::path_is_absolute(name)) { - fullname = name; - } else if (SP_ACTIVE_DOCUMENT->getBase()) { - fullname = Glib::build_filename(SP_ACTIVE_DOCUMENT->getBase(), name); - } else { - fullname = Glib::build_filename(Glib::get_current_dir(), name); - } - - - cmdline.append(" '"); - cmdline.append(fullname.c_str()); - cmdline.append("'"); - - //g_warning("##Command line: %s\n", cmdline.c_str()); - - g_spawn_command_line_async(cmdline.c_str(), - &errThing); - - if ( errThing ) { - g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message); - SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message); - g_error_free(errThing); - errThing = 0; - } -} - -/* Fill and Stroke entry */ -static void sp_fill_settings(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - if (sp_desktop_selection(desktop)->isEmpty()) { - sp_desktop_selection(desktop)->set(item); - } - - desktop->_dlg_mgr->showDialog("FillAndStroke"); -} - -/* SPShape */ -static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) -{ - SPItem *item; - GtkWidget *w; - - item = (SPItem *) object; - - /* Item dialog */ - w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_fill_settings), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); -} - -/* Edit Text entry */ -static void sp_text_settings(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - if (sp_desktop_selection(desktop)->isEmpty()) { - sp_desktop_selection(desktop)->set(item); - } - - desktop->_dlg_mgr->showDialog("TextFont"); -} - -/* Spellcheck entry */ -static void sp_spellcheck_settings(GtkMenuItem *menuitem, SPItem *item) -{ - SPDesktop *desktop; - - g_assert(SP_IS_ITEM(item)); - - desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop"); - g_return_if_fail(desktop != NULL); - - if (sp_desktop_selection(desktop)->isEmpty()) { - sp_desktop_selection(desktop)->set(item); - } - - desktop->_dlg_mgr->showDialog("SpellCheck"); -} - -/* SPText */ -static void sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) -{ - SPItem *item; - GtkWidget *w; - - item = (SPItem *) object; - - /* Fill and Stroke dialog */ - w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_fill_settings), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - - /* Edit Text dialog */ - w = gtk_menu_item_new_with_mnemonic(_("_Text and Font...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_text_settings), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); - - /* Spellcheck dialog */ - w = gtk_menu_item_new_with_mnemonic(_("Check Spellin_g...")); - g_object_set_data(G_OBJECT(w), "desktop", desktop); - g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_spellcheck_settings), item); - gtk_widget_show(w); - gtk_menu_shell_append(GTK_MENU_SHELL(m), w); -} -/* - 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 : +/*
+ * Unser-interface related object extension
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
+ *
+ * This code is in public domain
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ui/dialog/dialog-manager.h"
+#include "context-menu.h"
+#include "../xml/repr.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "helper/action.h" //sp_action_perform
+#include "inkscape.h"
+#include "message-stack.h"
+#include "preferences.h"
+#include "verbs.h"
+
+using Inkscape::DocumentUndo;
+
+static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+
+/* Append object-specific part to context menu */
+
+void sp_object_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
+{
+ GObjectClass *klass;
+ klass = G_OBJECT_GET_CLASS(object);
+ while (G_TYPE_CHECK_CLASS_TYPE((klass), SP_TYPE_OBJECT)) {
+ GType type;
+ type = G_TYPE_FROM_CLASS(klass);
+ sp_object_type_menu(type, object, desktop, menu);
+ klass = (GObjectClass*)g_type_class_peek_parent(klass);
+ }
+}
+
+/* Implementation */
+
+#include <gtk/gtk.h>
+#include <glibmm/i18n.h>
+
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "sp-anchor.h"
+#include "sp-clippath.h"
+#include "sp-image.h"
+#include "sp-mask.h"
+#include "sp-path.h"
+#include "sp-text.h"
+#include "desktop-handles.h"
+#include "ui/dialog/object-attributes.h"
+#include "ui/dialog/object-properties.h"
+#include "ui/dialog/spellcheck.h"
+
+
+static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+static void sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+
+static void sp_object_type_menu(GType type, SPObject *object, SPDesktop *desktop, GtkMenu *menu)
+{
+ static GHashTable *t2m = NULL;
+ void (* handler)(SPObject *object, SPDesktop *desktop, GtkMenu *menu);
+ if (!t2m) {
+ t2m = g_hash_table_new(NULL, NULL);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ITEM), (void*)sp_item_menu);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_GROUP), (void*)sp_group_menu);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_ANCHOR), (void*)sp_anchor_menu);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_IMAGE), (void*)sp_image_menu);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_SHAPE), (void*)sp_shape_menu);
+ g_hash_table_insert(t2m, GUINT_TO_POINTER(SP_TYPE_TEXT), (void*)sp_text_menu);
+ }
+ handler = (void (*)(SPObject*, SPDesktop*, GtkMenu*))g_hash_table_lookup(t2m, GUINT_TO_POINTER(type));
+ if (handler) handler(object, desktop, menu);
+}
+
+/* SPItem */
+
+static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item);
+static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item);
+static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item);
+static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item);
+static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item);
+static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item);
+static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item);
+
+/* Generate context menu item section */
+static void sp_item_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
+{
+ SPItem *item;
+ GtkWidget *w;
+
+ item = (SPItem *) object;
+
+ /* Item dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("_Object Properties..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_properties), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Separator */
+ w = gtk_menu_item_new();
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Select item */
+ w = gtk_menu_item_new_with_mnemonic(_("_Select This"));
+ if (sp_desktop_selection(desktop)->includes(item)) {
+ gtk_widget_set_sensitive(w, FALSE);
+ } else {
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_select_this), item);
+ }
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Create link */
+ w = gtk_menu_item_new_with_mnemonic(_("_Create Link"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_create_link), item);
+ gtk_widget_set_sensitive(w, !SP_IS_ANCHOR(item));
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Set mask */
+ w = gtk_menu_item_new_with_mnemonic(_("Set Mask"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_set_mask), item);
+ if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
+ gtk_widget_set_sensitive(w, FALSE);
+ } else {
+ gtk_widget_set_sensitive(w, TRUE);
+ }
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Release mask */
+ w = gtk_menu_item_new_with_mnemonic(_("Release Mask"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_release_mask), item);
+ if (item && item->mask_ref && item->mask_ref->getObject()) {
+ gtk_widget_set_sensitive(w, TRUE);
+ } else {
+ gtk_widget_set_sensitive(w, FALSE);
+ }
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Set Clip */
+ w = gtk_menu_item_new_with_mnemonic(_("Set _Clip"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_set_clip), item);
+ if ((item && item->mask_ref && item->mask_ref->getObject()) || (item->clip_ref && item->clip_ref->getObject())) {
+ gtk_widget_set_sensitive(w, FALSE);
+ } else {
+ gtk_widget_set_sensitive(w, TRUE);
+ }
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Release Clip */
+ w = gtk_menu_item_new_with_mnemonic(_("Release C_lip"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_release_clip), item);
+ if (item && item->clip_ref && item->clip_ref->getObject()) {
+ gtk_widget_set_sensitive(w, TRUE);
+ } else {
+ gtk_widget_set_sensitive(w, FALSE);
+ }
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+
+}
+
+static void sp_item_properties(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_desktop_selection(desktop)->set(item);
+
+ // sp_item_dialog();
+ desktop->_dlg_mgr->showDialog("ObjectProperties");
+}
+
+
+static void sp_set_mask(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_selection_set_mask(desktop, false, false);
+}
+
+
+static void sp_release_mask(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_selection_unset_mask(desktop, false);
+}
+
+
+static void sp_set_clip(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_selection_set_mask(desktop, true, false);
+}
+
+
+static void sp_release_clip(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_selection_unset_mask(desktop, true);
+}
+
+
+static void sp_item_select_this(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ sp_desktop_selection(desktop)->set(item);
+}
+
+static void sp_item_create_link(GtkMenuItem *menuitem, SPItem *item)
+{
+ g_assert(SP_IS_ITEM(item));
+ g_assert(!SP_IS_ANCHOR(item));
+
+ SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ Inkscape::XML::Node *repr = xml_doc->createElement("svg:a");
+ item->parent->getRepr()->addChild(repr, item->getRepr());
+ SPObject *object = item->document->getObjectByRepr(repr);
+ g_return_if_fail(SP_IS_ANCHOR(object));
+
+ const char *id = item->getRepr()->attribute("id");
+ Inkscape::XML::Node *child = item->getRepr()->duplicate(xml_doc);
+ item->deleteObject(false);
+ repr->addChild(child, NULL);
+ child->setAttribute("id", id);
+
+ Inkscape::GC::release(repr);
+ Inkscape::GC::release(child);
+
+ DocumentUndo::done(object->document, SP_VERB_NONE,
+ _("Create link"));
+
+ sp_desktop_selection(desktop)->set(SP_ITEM(object));
+ desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+/* SPGroup */
+
+static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group);
+
+static void sp_group_menu(SPObject *object, SPDesktop *desktop, GtkMenu *menu)
+{
+ SPItem *item=SP_ITEM(object);
+ GtkWidget *w;
+
+ /* "Ungroup" */
+ w = gtk_menu_item_new_with_mnemonic(_("_Ungroup"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_item_group_ungroup_activate), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
+}
+
+static void sp_item_group_ungroup_activate(GtkMenuItem *menuitem, SPGroup *group)
+{
+ SPDesktop *desktop;
+ GSList *children;
+
+ g_assert(SP_IS_GROUP(group));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ children = NULL;
+ sp_item_group_ungroup(group, &children);
+
+ sp_desktop_selection(desktop)->setList(children);
+ g_slist_free(children);
+}
+
+/* SPAnchor */
+
+static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
+static void sp_anchor_link_follow(GtkMenuItem *menuitem, SPAnchor *anchor);
+static void sp_anchor_link_remove(GtkMenuItem *menuitem, SPAnchor *anchor);
+
+static void sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
+{
+ SPItem *item;
+ GtkWidget *w;
+
+ item = (SPItem *) object;
+
+ /* Link dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("Link _Properties..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_properties), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Select item */
+ w = gtk_menu_item_new_with_mnemonic(_("_Follow Link"));
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_follow), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ /* Reset transformations */
+ w = gtk_menu_item_new_with_mnemonic(_("_Remove Link"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_anchor_link_remove), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+}
+
+static void sp_anchor_link_properties(GtkMenuItem *menuitem, SPAnchor */*anchor*/)
+{
+ SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+ desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+static void sp_anchor_link_follow(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
+{
+ g_return_if_fail(anchor != NULL);
+ g_return_if_fail(SP_IS_ANCHOR(anchor));
+
+ /* shell out to an external browser here */
+}
+
+static void sp_anchor_link_remove(GtkMenuItem */*menuitem*/, SPAnchor *anchor)
+{
+ GSList *children;
+
+ g_return_if_fail(anchor != NULL);
+ g_return_if_fail(SP_IS_ANCHOR(anchor));
+
+ children = NULL;
+ sp_item_group_ungroup(SP_GROUP(anchor), &children);
+
+ g_slist_free(children);
+}
+
+/* Image */
+
+static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor *anchor);
+static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor);
+static void sp_image_image_embed(GtkMenuItem *menuitem, SPItem *item);
+static void sp_image_image_extract(GtkMenuItem *menuitem, SPItem *item);
+
+static void sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
+{
+ SPItem *item = SP_ITEM(object);
+ GtkWidget *w;
+ Inkscape::XML::Node *ir = object->getRepr();
+ const gchar *href = ir->attribute("xlink:href");
+
+ /* Image properties */
+ w = gtk_menu_item_new_with_mnemonic(_("Image _Properties..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_properties), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+
+ /* Edit externally */
+ w = gtk_menu_item_new_with_mnemonic(_("Edit Externally..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_edit), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
+ gtk_widget_set_sensitive( w, FALSE );
+ }
+
+ /* Embed image */
+ w = gtk_menu_item_new_with_mnemonic(C_("Context menu", "Embed Image"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_embed), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) {
+ gtk_widget_set_sensitive( w, FALSE );
+ }
+
+ /* Extract image */
+ w = gtk_menu_item_new_with_mnemonic(C_("Context menu", "Extract Image"));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_image_image_extract), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+ if ( (!href) || ((strncmp(href, "data:", 5) != 0)) ) {
+ gtk_widget_set_sensitive( w, FALSE );
+ }
+}
+
+/* Image Properties entry */
+static void sp_image_image_properties(GtkMenuItem *menuitem, SPAnchor */*anchor*/)
+{
+ SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+ desktop->_dlg_mgr->showDialog("ObjectAttributes");
+}
+
+static gchar* getImageEditorName() {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gchar* value = 0;
+ Glib::ustring choices = prefs->getString("/options/bitmapeditor/value");
+ if (!choices.empty()) {
+ value = g_strdup(choices.c_str());
+ }
+ if (!value) {
+ value = g_strdup("gimp");
+ }
+ return value;
+}
+
+/* Edit Externally entry */
+static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor)
+{
+ SPObject* obj = anchor;
+ Inkscape::XML::Node *ir = obj->getRepr();
+ const gchar *href = ir->attribute("xlink:href");
+
+ GError* errThing = 0;
+ Glib::ustring cmdline = getImageEditorName();
+ Glib::ustring name;
+ Glib::ustring fullname;
+
+#ifdef WIN32
+ // g_spawn_command_line_sync parsing is done according to Unix shell rules,
+ // not Windows command interpreter rules. Thus we need to enclose the
+ // executable path with sigle quotes.
+ int index = cmdline.find(".exe");
+ if ( index < 0 ) index = cmdline.find(".bat");
+ if ( index < 0 ) index = cmdline.find(".com");
+ if ( index >= 0 ) {
+ Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str();
+ Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str();
+ editorBin.insert(0, "'");
+ editorBin.append("'");
+ cmdline = editorBin;
+ cmdline.append(args);
+ } else {
+ // Enclose the whole command line if no executable path can be extracted.
+ cmdline.insert(0, "'");
+ cmdline.append("'");
+ }
+#endif
+
+ if (strncmp (href,"file:",5) == 0) {
+ // URI to filename conversion
+ name = g_filename_from_uri(href, NULL, NULL);
+ } else {
+ name.append(href);
+ }
+
+ if (Glib::path_is_absolute(name)) {
+ fullname = name;
+ } else if (SP_ACTIVE_DOCUMENT->getBase()) {
+ fullname = Glib::build_filename(SP_ACTIVE_DOCUMENT->getBase(), name);
+ } else {
+ fullname = Glib::build_filename(Glib::get_current_dir(), name);
+ }
+
+ cmdline.append(" '");
+ cmdline.append(fullname.c_str());
+ cmdline.append("'");
+
+ //g_warning("##Command line: %s\n", cmdline.c_str());
+
+ g_spawn_command_line_async(cmdline.c_str(),
+ &errThing);
+
+ if ( errThing ) {
+ g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message);
+ SPDesktop *desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, errThing->message);
+ g_error_free(errThing);
+ errThing = 0;
+ }
+}
+
+/* Embed Image entry */
+static void sp_image_image_embed(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ if (sp_desktop_selection(desktop)->isEmpty()) {
+ sp_desktop_selection(desktop)->set(item);
+ }
+
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" );
+ if (verb) {
+ SPAction *action = verb->get_action(desktop);
+ if (action) {
+ sp_action_perform(action, NULL);
+ }
+ }
+}
+
+/* Extract Image entry */
+static void sp_image_image_extract(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ if (sp_desktop_selection(desktop)->isEmpty()) {
+ sp_desktop_selection(desktop)->set(item);
+ }
+
+ Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" );
+ if (verb) {
+ SPAction *action = verb->get_action(desktop);
+ if (action) {
+ sp_action_perform(action, NULL);
+ }
+ }
+}
+
+/* Fill and Stroke entry */
+static void sp_fill_settings(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ if (sp_desktop_selection(desktop)->isEmpty()) {
+ sp_desktop_selection(desktop)->set(item);
+ }
+
+ desktop->_dlg_mgr->showDialog("FillAndStroke");
+}
+
+/* SPShape */
+static void sp_shape_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
+{
+ SPItem *item;
+ GtkWidget *w;
+
+ item = (SPItem *) object;
+
+ /* Item dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_fill_settings), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+}
+
+/* Edit Text entry */
+static void sp_text_settings(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ if (sp_desktop_selection(desktop)->isEmpty()) {
+ sp_desktop_selection(desktop)->set(item);
+ }
+
+ desktop->_dlg_mgr->showDialog("TextFont");
+}
+
+/* Spellcheck entry */
+static void sp_spellcheck_settings(GtkMenuItem *menuitem, SPItem *item)
+{
+ SPDesktop *desktop;
+
+ g_assert(SP_IS_ITEM(item));
+
+ desktop = (SPDesktop*)g_object_get_data(G_OBJECT(menuitem), "desktop");
+ g_return_if_fail(desktop != NULL);
+
+ if (sp_desktop_selection(desktop)->isEmpty()) {
+ sp_desktop_selection(desktop)->set(item);
+ }
+
+ desktop->_dlg_mgr->showDialog("SpellCheck");
+}
+
+/* SPText */
+static void sp_text_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m)
+{
+ SPItem *item;
+ GtkWidget *w;
+
+ item = (SPItem *) object;
+
+ /* Fill and Stroke dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("_Fill and Stroke..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_fill_settings), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+
+ /* Edit Text dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("_Text and Font..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_text_settings), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+
+ /* Spellcheck dialog */
+ w = gtk_menu_item_new_with_mnemonic(_("Check Spellin_g..."));
+ g_object_set_data(G_OBJECT(w), "desktop", desktop);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(sp_spellcheck_settings), item);
+ gtk_widget_show(w);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m), w);
+}
+/*
+ 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 :
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 6c9cbd63e..5030f17be 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -30,6 +30,7 @@ #include <iostream> #include "enums.h" #include "desktop-handles.h" +#include "extension/internal/gdkpixbuf-input.h" #include "message-stack.h" #include "style.h" #include "selection.h" @@ -481,14 +482,14 @@ void InkscapePreferences::initPageUI() _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"), _("Esperanto (eo)"), _("Estonian (et)"), _("Farsi (fa)"), _("Finnish (fi)"), _("French (fr)"), _("Irish (ga)"), _("Galician (gl)"), _("Hebrew (he)"), _("Hungarian (hu)"), - _("Indonesian (id)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Macedonian (mk)"), + _("Indonesian (id)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Latvian (lv)"), _("Macedonian (mk)"), _("Mongolian (mn)"), _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"), _("Panjabi (pa)"), _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), _("Romanian (ro)"), _("Russian (ru)"), _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"), _("Swedish (sv)"),_("Telugu (te_IN)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")}; Glib::ustring langValues[] = {"", "sq", "am", "ar", "hy", "az", "eu", "be", "bg", "bn", "br", "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", "da", "nl", "dz", "de", "el", "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", "fa", "fi", "fr", "ga", - "gl", "he", "hu", "id", "it", "ja", "km", "rw", "ko", "lt", "mk", "mn", "ne", "nb", "nn", "pa", + "gl", "he", "hu", "id", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "pa", "pl", "pt", "pt_BR", "ro", "ru", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "te_IN", "th", "tr", "uk", "vi" }; { @@ -1306,6 +1307,12 @@ void InkscapePreferences::initPageBitmaps() _bitmap_copy_res.init("/options/createbitmap/resolution", 1.0, 6000.0, 1.0, 1.0, PX_PER_IN, true, false); _page_bitmaps.add_line( false, _("Resolution for Create Bitmap Copy:"), _bitmap_copy_res, _("dpi"), _("Resolution used by the Create Bitmap Copy command"), false); + { + Glib::ustring labels[] = {_("Always embed"), _("Always link"), _("Ask")}; + Glib::ustring values[] = {"embed", "link", "ask"}; + _bitmap_import.init("/dialogs/import/link", labels, values, G_N_ELEMENTS(values), "ask"); + _page_bitmaps.add_line( false, _("Bitmap import:"), _bitmap_import, "", "", false); + } this->AddPage(_page_bitmaps, _("Bitmaps"), PREFS_PAGE_BITMAPS); } diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 5b5fe9822..f9944f8c0 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -322,6 +322,7 @@ protected: UI::Widget::PrefEntryFileButtonHBox _misc_bitmap_editor; UI::Widget::PrefCheckButton _misc_bitmap_autoreload; UI::Widget::PrefSpinButton _bitmap_copy_res; + UI::Widget::PrefCombo _bitmap_import; UI::Widget::PrefCheckButton _save_use_current_dir; UI::Widget::PrefCheckButton _save_autosave_enable; diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp index b1500c7fd..3bd047ebc 100644 --- a/src/ui/dialog/layers.cpp +++ b/src/ui/dialog/layers.cpp @@ -529,6 +529,8 @@ void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::T Glib::ustring tmp = row[_model->_colLabel]; if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) { _desktop->layer_manager->renameLayer( obj, tmp.c_str(), FALSE ); + DocumentUndo::done( _desktop->doc() , SP_VERB_NONE, + _("Renamed layer")); } } } diff --git a/src/ui/dialog/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp index b890739fb..c766bae9d 100644 --- a/src/ui/dialog/ocaldialogs.cpp +++ b/src/ui/dialog/ocaldialogs.cpp @@ -647,8 +647,7 @@ void ImportDialog::on_list_results_selection_changed() if (((int) pathlist.size()) < 1) { return; } - posArray = pathlist[0].get_indices(); - int row = posArray[0]; + int row = pathlist[0][0]; Glib::ustring guid = list_results->get_text(row, RESULTS_COLUMN_GUID); @@ -666,8 +665,7 @@ void ImportDialog::on_button_import_clicked() { if (((int) pathlist.size()) < 1) { return; } - posArray = pathlist[0].get_indices(); - int row = posArray[0]; + int row = pathlist[0][0]; button_import->set_sensitive(false); button_close->hide(); @@ -689,8 +687,7 @@ void ImportDialog::on_list_results_cursor_changed() if (((int) pathlist.size()) < 1) { return; } - posArray = pathlist[0].get_indices(); - int row = posArray[0]; + int row = pathlist[0][0]; if (downloading_thumbnail) { cancellable_thumbnail->cancel(); diff --git a/src/ui/widget/color-preview.cpp b/src/ui/widget/color-preview.cpp index 8bb523831..244e2b4e3 100644 --- a/src/ui/widget/color-preview.cpp +++ b/src/ui/widget/color-preview.cpp @@ -114,6 +114,54 @@ ColorPreview::paint (GdkRectangle *area) cairo_destroy(ct); } +GdkPixbuf* +ColorPreview::toPixbuf (int width, int height) +{ + GdkRectangle carea; + gint w2; + w2 = width / 2; + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *ct = cairo_create(s); + + /* Transparent area */ + carea.x = 0; + carea.y = 0; + carea.width = w2; + carea.height = height; + + cairo_pattern_t *checkers = ink_cairo_pattern_create_checkerboard(); + + cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height); + cairo_set_source(ct, checkers); + cairo_fill_preserve(ct); + ink_cairo_set_source_rgba32(ct, _rgba); + cairo_fill(ct); + + cairo_pattern_destroy(checkers); + + /* Solid area */ + carea.x = w2; + carea.y = 0; + carea.width = width - w2; + carea.height = height; + + cairo_rectangle(ct, carea.x, carea.y, carea.width, carea.height); + ink_cairo_set_source_rgba32(ct, _rgba | 0xff); + cairo_fill(ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + width, height, cairo_image_surface_get_stride(s), + ink_cairo_pixbuf_cleanup, s); + convert_pixbuf_argb32_to_normal(pixbuf); + + return pixbuf; +} + }}} /* diff --git a/src/ui/widget/color-preview.h b/src/ui/widget/color-preview.h index f89e0ea42..d6d3da01c 100644 --- a/src/ui/widget/color-preview.h +++ b/src/ui/widget/color-preview.h @@ -24,13 +24,14 @@ class ColorPreview : public Gtk::Widget { public: ColorPreview (guint32 rgba); void setRgba32 (guint32 rgba); + GdkPixbuf* toPixbuf (int width, int height); protected: virtual void on_size_request (Gtk::Requisition *req); virtual void on_size_allocate (Gtk::Allocation &all); virtual bool on_expose_event (GdkEventExpose *event); void paint (GdkRectangle *area); - + guint32 _rgba; }; diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 6fe21319d..a2519d4bb 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -22,26 +22,35 @@ namespace UI { namespace Widget { SimpleFilterModifier::SimpleFilterModifier(int flags) - : _lb_blend(_("Blend mode:")), -#if WITH_GTKMM_2_22 - _lb_blur(_("_Blur:"), Gtk::ALIGN_START, Gtk::ALIGN_CENTER, true), -#else - _lb_blur(_("_Blur:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true), -#endif + : _hb_blur(false, 0), + _lb_blend(_("Blend mode:")), + _lb_blur(_("_Blur:")), _blend(BlendModeConverter, SP_ATTR_INVALID, false), - _blur(0, 0, 100, 1, 0.01, 2) + _blur(0, 0, 100, 1, 0.01, 1) { _flags = flags; if (flags & BLEND) { add(_hb_blend); - _hb_blend.pack_start(_lb_blend, false, false); + _hb_blend.pack_start(_lb_blend); _hb_blend.pack_start(_blend); } if (flags & BLUR) { - add(_vb_blur); - _vb_blur.add(_lb_blur); - _vb_blur.add(_blur); + add(_hb_blur); + /* + * Hack to get a min size of label, but still be able to expand if needed + * Should match ObjectCompositeSettings::_opacity_label + */ + if (_lb_blur.get_text().length() < 7) { + _lb_blur.set_width_chars(7); + } + #if WITH_GTKMM_2_22 + _lb_blur.set_alignment(Gtk::ALIGN_END, Gtk::ALIGN_CENTER); + #else + _lb_blur.set_alignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER); + #endif + _hb_blur.pack_start(_lb_blur, false, false, 0); + _hb_blur.pack_start(_blur, true, true, 0); } show_all_children(); diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h index 3c3da6c2d..2d41eb3bf 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -49,7 +49,7 @@ public: private: int _flags; Gtk::HBox _hb_blend; - Gtk::VBox _vb_blur; + Gtk::HBox _hb_blur; Gtk::Label _lb_blend, _lb_blur; ComboBoxEnum<Inkscape::Filters::FilterBlendMode> _blend; SpinSlider _blur; diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index afeec5492..9613f2d4f 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -62,8 +62,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _blur_tag(Glib::ustring(history_prefix) + ":blur"), _opacity_tag(Glib::ustring(history_prefix) + ":opacity"), _opacity_vbox(false, 0), - _opacity_label_box(false, 0), - _opacity_label(_("_Opacity (%):"), 0.0, 1.0, true), + _opacity_label(_("Opacity:")), _opacity_adjustment(100.0, 0.0, 100.0, 1.0, 1.0, 0.0), _opacity_hscale(_opacity_adjustment), _opacity_spin_button(_opacity_adjustment, 0.01, 1), @@ -72,6 +71,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _fe_alignment(1, 1, 1, 1), _blocked(false) { + // Filter Effects pack_start(_fe_vbox, false, false, 2); _fe_alignment.set_padding(0, 0, 4, 0); @@ -81,10 +81,19 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co // Opacity pack_start(_opacity_vbox, false, false, 2); - _opacity_label_box.pack_start(_opacity_label, false, false, 4); - _opacity_vbox.pack_start(_opacity_label_box, false, false, 0); + if (_opacity_label.get_text().length() < 7) { + _opacity_label.set_width_chars(7); + } +#if WITH_GTKMM_2_22 + _opacity_label.set_alignment(Gtk::ALIGN_END, Gtk::ALIGN_CENTER); +#else + _opacity_label.set_alignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER); +#endif + + _opacity_hbox.pack_start(_opacity_label, false, false, 3); + //_opacity_vbox.pack_start(_opacity_label_box, false, false, 0); _opacity_vbox.pack_start(_opacity_hbox, false, false, 0); - _opacity_hbox.pack_start(_opacity_hscale, true, true, 4); + _opacity_hbox.pack_start(_opacity_hscale, true, true, 0); _opacity_hbox.pack_start(_opacity_spin_button, false, false, 0); _opacity_hscale.set_draw_value(false); _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_opacityValueChanged)); diff --git a/src/ui/widget/object-composite-settings.h b/src/ui/widget/object-composite-settings.h index 7b0e9b994..d05839a03 100644 --- a/src/ui/widget/object-composite-settings.h +++ b/src/ui/widget/object-composite-settings.h @@ -45,7 +45,6 @@ private: Glib::ustring _opacity_tag; Gtk::VBox _opacity_vbox; - Gtk::HBox _opacity_label_box; Gtk::HBox _opacity_hbox; Gtk::Label _opacity_label; Gtk::Adjustment _opacity_adjustment; diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index fec351ab0..a7b51d535 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -386,8 +386,12 @@ ZoomCorrRuler::redraw() { Glib::RefPtr<Gdk::Window> window = get_window(); Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context(); +#if WITH_GTKMM_2_24 + int w = window->get_width(); +#else int w, h; window->get_size(w, h); +#endif _drawing_width = w - _border * 2; cr->set_source_rgb(1.0, 1.0, 1.0); diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 418cc5c6f..7b76ccc83 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -30,6 +30,7 @@ set(widgets_SRC sp-xmlview-tree.cpp spinbutton-events.cpp spw-utilities.cpp + stroke-marker-selector.cpp stroke-style.cpp swatch-selector.cpp toolbox.cpp @@ -68,6 +69,7 @@ set(widgets_SRC sp-xmlview-tree.h spinbutton-events.h spw-utilities.h + stroke-marker-selector.h stroke-style.h swatch-selector.h toolbox.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 86046b918..255767d43 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -62,6 +62,8 @@ ink_common_sources += \ widgets/sp-xmlview-content.h \ widgets/sp-xmlview-tree.cpp \ widgets/sp-xmlview-tree.h \ + widgets/stroke-marker-selector.cpp \ + widgets/stroke-marker-selector.h \ widgets/stroke-style.cpp \ widgets/stroke-style.h \ widgets/swatch-selector.cpp \ diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index 09a06370d..b835dc36b 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -153,6 +153,37 @@ sp_gradient_image_new (SPGradient *gradient) return (GtkWidget *) image; } +GdkPixbuf* +sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) +{ + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *ct = cairo_create(s); + + cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); + cairo_set_source(ct, check); + cairo_paint(ct); + cairo_pattern_destroy(check); + + if (gr) { + cairo_pattern_t *p = sp_gradient_create_preview_pattern(gr, width); + cairo_set_source(ct, p); + cairo_paint(ct); + cairo_pattern_destroy(p); + } + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), + GDK_COLORSPACE_RGB, TRUE, 8, + width, height, cairo_image_surface_get_stride(s), + ink_cairo_pixbuf_cleanup, s); + convert_pixbuf_argb32_to_normal(pixbuf); + + return pixbuf; +} + + void sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) { diff --git a/src/widgets/gradient-image.h b/src/widgets/gradient-image.h index 0fbed879f..904ce4cac 100644 --- a/src/widgets/gradient-image.h +++ b/src/widgets/gradient-image.h @@ -43,6 +43,7 @@ struct SPGradientImageClass { GType sp_gradient_image_get_type (void); GtkWidget *sp_gradient_image_new (SPGradient *gradient); +GdkPixbuf *sp_gradient_to_pixbuf (SPGradient *gr, int width, int height); void sp_gradient_image_set_gradient (SPGradientImage *gi, SPGradient *gr); #endif diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 6443e09cb..2e7d6b89d 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -141,35 +141,54 @@ void gr_apply_gradient (Inkscape::Selection *selection, GrDrag *drag, SPGradient } } -void gr_item_activate (GtkMenuItem *menuitem, gpointer data) +void gr_combo_box_changed (GtkComboBox *widget, gpointer data) { - SPGradient *gr = static_cast<SPGradient *>(g_object_get_data (G_OBJECT (menuitem), "gradient")); - gr = sp_gradient_ensure_vector_normalized(gr); + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (widget, &iter)) { + return; + } - SPDesktop *desktop = static_cast<SPDesktop *>(data); - Inkscape::Selection *selection = sp_desktop_selection (desktop); - SPEventContext *ev = sp_desktop_event_context (desktop); + GtkTreeModel *model = gtk_combo_box_get_model (widget); + SPGradient *gr = NULL; + gtk_tree_model_get (model, &iter, 2, &gr, -1); - gr_apply_gradient (selection, ev? ev->get_drag() : NULL, gr); + if (gr) { + gr = sp_gradient_ensure_vector_normalized(gr); - DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, - _("Assign gradient to object")); -} + SPDesktop *desktop = static_cast<SPDesktop *>(data); + Inkscape::Selection *selection = sp_desktop_selection (desktop); + SPEventContext *ev = sp_desktop_event_context (desktop); + + gr_apply_gradient (selection, ev? ev->get_drag() : NULL, gr); + + DocumentUndo::done(sp_desktop_document (desktop), SP_VERB_CONTEXT_GRADIENT, + _("Assign gradient to object")); + } -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 ("<small>#%s</small>", id+15); - return g_strdup_printf ("<small>%s</small>", id); } + + GtkWidget *gr_vector_list(SPDesktop *desktop, bool selection_empty, SPGradient *gr_selected, bool gr_multi) { SPDocument *document = sp_desktop_document (desktop); - GtkWidget *om = gtk_option_menu_new (); - GtkWidget *m = gtk_menu_new (); + GtkListStore *store; + GtkTreeIter iter; + GtkCellRenderer *renderer; + GtkWidget *combo_box; + + store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + 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); GSList *gl = NULL; const GSList *gradients = document->getResourceList("gradient"); @@ -186,87 +205,65 @@ GtkWidget *gr_vector_list(SPDesktop *desktop, bool selection_empty, SPGradient * if (!gl) { // The document has no gradients - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>No gradients</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); - gtk_widget_set_sensitive (om, FALSE); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("No gradients"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } else if (selection_empty) { // Document has gradients, but nothing is currently selected. - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>Nothing selected</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); - gtk_widget_set_sensitive (om, FALSE); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("Nothing selected"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } else { if (gr_selected == NULL) { - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>No gradients in selection</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("No gradient"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } if (gr_multi) { - GtkWidget *l = gtk_label_new(""); - gtk_label_set_markup (GTK_LABEL(l), _("<small>Multiple gradients</small>")); - GtkWidget *i = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER (i), l); - gtk_widget_show (i); - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, NULL, 1, _("Multiple gradients"), 2, NULL, -1); + gtk_widget_set_sensitive (combo_box, FALSE); + } while (gl) { SPGradient *gradient = SP_GRADIENT (gl->data); gl = g_slist_remove (gl, gradient); - GtkWidget *i = gtk_menu_item_new (); - g_object_set_data (G_OBJECT (i), "gradient", gradient); - g_signal_connect (G_OBJECT (i), "activate", G_CALLBACK (gr_item_activate), desktop); - - GtkWidget *image = sp_gradient_image_new (gradient); - - GtkWidget *hb = gtk_hbox_new (FALSE, 4); - GtkWidget *l = gtk_label_new (""); gchar *label = gr_prepare_label(gradient); - gtk_label_set_markup (GTK_LABEL(l), label); + GdkPixbuf *pixb = sp_gradient_to_pixbuf (gradient, 64, 18); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, pixb, 1, label, 2, gradient, -1); g_free (label); - gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5); - gtk_box_pack_start (GTK_BOX (hb), l, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (hb), image, FALSE, FALSE, 0); - - gtk_widget_show_all (i); - - gtk_container_add (GTK_CONTAINER (i), hb); - - gtk_menu_shell_append(GTK_MENU_SHELL (m), i); if (gradient == gr_selected) { pos = idx; } idx ++; } - gtk_widget_set_sensitive (om, TRUE); + gtk_widget_set_sensitive (combo_box, TRUE); } - gtk_option_menu_set_menu (GTK_OPTION_MENU (om), m); /* Select the current gradient, or the Multi/Nothing line */ - if (gr_multi || gr_selected == NULL) - gtk_option_menu_set_history (GTK_OPTION_MENU (om), 0); - else - gtk_option_menu_set_history (GTK_OPTION_MENU (om), pos); + if (gr_multi || gr_selected == NULL) { + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0); + } + else { + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , pos); + } + + sp_set_font_size_smaller(combo_box); - return om; + g_signal_connect (G_OBJECT (combo_box), "changed", G_CALLBACK (gr_combo_box_changed), desktop); + + return combo_box; } @@ -377,10 +374,10 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe if (selection) { SPEventContext *ev = sp_desktop_event_context(desktop); - GtkWidget *om = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "menu"); - if (om) { - gtk_widget_destroy(om); - om = 0; + GtkWidget *combo_box = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "combobox"); + if (combo_box) { + gtk_widget_destroy(combo_box); + combo_box = 0; } SPGradient *gr_selected = 0; @@ -391,13 +388,13 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe gr_read_selection(selection, ev ? ev->get_drag() : 0, gr_selected, gr_multi, spr_selected, spr_multi); - om = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); - g_object_set_data(G_OBJECT(widget), "menu", om); + combo_box = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); + g_object_set_data(G_OBJECT(widget), "combobox", combo_box); GtkWidget *buttons = (GtkWidget *) g_object_get_data(G_OBJECT(widget), "buttons"); gtk_widget_set_sensitive(buttons, (gr_selected && !gr_multi)); - gtk_box_pack_start(GTK_BOX(widget), om, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(widget), combo_box, TRUE, TRUE, 0); gtk_widget_show_all(widget); } @@ -436,13 +433,19 @@ static void gr_disconnect_sigc (GObject */*obj*/, sigc::connection *connection) static void gr_edit (GtkWidget */*button*/, GtkWidget *widget) { - GtkWidget *om = (GtkWidget *) g_object_get_data (G_OBJECT(widget), "menu"); + GtkWidget *combo_box = (GtkWidget *) g_object_get_data (G_OBJECT(widget), "combobox"); spinbutton_defocus(GTK_OBJECT(widget)); - if (om) { - GtkWidget *i = gtk_menu_get_active (GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (om)))); - SPGradient *gr = (SPGradient *) g_object_get_data (G_OBJECT(i), "gradient"); + if (combo_box) { + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { + return; + } + + GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + SPGradient *gr = NULL; + gtk_tree_model_get (model, &iter, 2, &gr, -1); if (gr) { GtkWidget *dialog = sp_gradient_vector_editor_new (gr); @@ -469,10 +472,10 @@ GtkWidget * gr_change_widget(SPDesktop *desktop) g_object_set_data(G_OBJECT(widget), "dtw", desktop->canvas); g_object_set_data (G_OBJECT (widget), "desktop", desktop); - GtkWidget *om = gr_vector_list (desktop, selection->isEmpty(), gr_selected, gr_multi); - g_object_set_data (G_OBJECT (widget), "menu", om); + GtkWidget *combo_box = gr_vector_list(desktop, selection->isEmpty(), gr_selected, gr_multi); + g_object_set_data(G_OBJECT(widget), "combobox", combo_box); - gtk_box_pack_start (GTK_BOX (widget), om, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (widget), combo_box, TRUE, TRUE, 0); { GtkWidget *buttons = gtk_hbox_new(FALSE, 1); @@ -628,9 +631,9 @@ sp_gradient_toolbox_new(SPDesktop *desktop) { GtkWidget *vectors = gr_change_widget (desktop); - GtkToolItem *vectors_toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(vectors_toolitem), vectors); - gtk_toolbar_insert(GTK_TOOLBAR(tbl), vectors_toolitem, -1); + GtkToolItem *vectors_toolitem = gtk_tool_item_new(); + gtk_container_add(GTK_CONTAINER(vectors_toolitem), vectors); + gtk_toolbar_insert(GTK_TOOLBAR(tbl), vectors_toolitem, -1); } gtk_widget_show_all(tbl); diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index eb421ade6..d6de0c492 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -63,7 +63,8 @@ static void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs); static void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs); static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs); -static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs); +static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs); +static SPStop *get_selected_stop( GtkWidget *vb); static GtkVBoxClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; @@ -132,9 +133,23 @@ static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs) new (&gvs->defs_release_connection) sigc::connection(); new (&gvs->defs_modified_connection) sigc::connection(); - gvs->menu = gtk_option_menu_new(); - gtk_widget_show(gvs->menu); - gtk_box_pack_start(GTK_BOX(gvs), gvs->menu, TRUE, TRUE, 0); + gvs->store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + gvs->combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (gvs->store)); + gvs->combo_connection = g_signal_connect (G_OBJECT (gvs->combo_box), "changed", G_CALLBACK (gr_combo_box_changed), gvs); + + GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, FALSE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->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 (gvs->combo_box), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "text", 1, NULL); + gtk_cell_renderer_set_padding(renderer, 0, 0); + + gtk_widget_show(gvs->combo_box); + gtk_box_pack_start(GTK_BOX(gvs), gvs->combo_box, TRUE, TRUE, 0); + } static void sp_gradient_vector_selector_destroy(GtkObject *object) @@ -219,7 +234,7 @@ void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPD 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 menus and stuff + // Harder case - keep document, rebuild list and stuff // fixme: (Lauris) suppress = TRUE; sp_gradient_vector_selector_set_gradient(gvs, NULL, NULL); @@ -246,16 +261,19 @@ SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *g return gvs->gr; } -static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) +gchar *gr_prepare_label (SPObject *obj) { - /* Clear old menu, if there is any */ - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(gvs->menu))) { - gtk_option_menu_remove_menu(GTK_OPTION_MENU(gvs->menu)); - } + 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); +} - /* Create new menu widget */ - GtkWidget *m = gtk_menu_new(); - gtk_widget_show(m); +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; @@ -274,112 +292,99 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) gint idx = 0; if (!gvs->doc) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No document selected")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + 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) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No gradients in document")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + 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) { - GtkWidget *i; - i = gtk_menu_item_new_with_label(_("No gradient selected")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(gvs->menu, FALSE); + 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 { while (gl) { SPGradient *gr; - GtkWidget *i, *w; gr = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gr); /* We have to know: */ /* Gradient destroy */ /* Gradient name change */ - i = gtk_menu_item_new(); - gtk_widget_show(i); - g_object_set_data(G_OBJECT(i), "gradient", gr); - g_signal_connect(G_OBJECT(i), "activate", G_CALLBACK(sp_gvs_gradient_activate), gvs); - - w = sp_gradient_image_new(gr); - gtk_widget_show(w); - - if (gvs->idlabel) { - GtkWidget *hb, *l; - hb = gtk_hbox_new(FALSE, 4); - gtk_widget_show(hb); - l = gtk_label_new(gr->getId()); - gtk_widget_show(l); - gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0); - w = hb; - } - gtk_container_add(GTK_CONTAINER(i), w); - - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); + 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->menu, TRUE); + gtk_widget_set_sensitive (gvs->combo_box, TRUE); } - gtk_option_menu_set_menu(GTK_OPTION_MENU(gvs->menu), m); - /* Set history */ - gtk_option_menu_set_history(GTK_OPTION_MENU(gvs->menu), pos); + /* 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 sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector *gvs) +static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs) { - SPGradient *gr, *norm; + GtkTreeIter iter; + if (!gtk_combo_box_get_active_iter (widget, &iter)) { + return; + } - gr = (SPGradient*)g_object_get_data(G_OBJECT(mi), "gradient"); - /* Hmmm... bad things may happen here, if actual gradient is something new */ - /* Namely - menuitems etc. will be fucked up */ - /* Hmmm - probably we can just re-set it as menuitem data (Lauris) */ + SPGradient *gr = NULL; + gtk_tree_model_get (GTK_TREE_MODEL(gvs->store), &iter, 2, &gr, -1); - //g_print("SPGradientVectorSelector: gradient %s activated\n", gr->getId()); - //g_message("Setting to gradient %p swatch:%d solid:%d", gr, gr->isSwatch(), gr->isSolid()); + if (gr) { - 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); - } + 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"); + } - /* 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 */ @@ -445,16 +450,15 @@ 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 *mnu, SPGradient *gradient, SPStop *new_stop); +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); - GtkWidget *mnu = (GtkWidget *)g_object_get_data(G_OBJECT(vb), "stopmenu"); SPGradient *gradient = (SPGradient *)g_object_get_data(G_OBJECT(vb), "gradient"); - update_stop_list(mnu, gradient, NULL); + update_stop_list(vb, gradient, NULL); } //FIXME!!! We must also listen to attr changes on all children (i.e. stops) too, @@ -511,13 +515,15 @@ static void verify_grad(SPGradient *gradient) } } -static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop) +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_option_menu_set_history(GTK_OPTION_MENU(mnu), i); + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , i); break; } i++; @@ -525,7 +531,7 @@ static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *n } } -static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_stop) +static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop) { if (!SP_IS_GRADIENT(gradient)) { @@ -534,14 +540,19 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ blocked = TRUE; - /* Clear old menu, if there is any */ - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))) { - gtk_option_menu_remove_menu(GTK_OPTION_MENU(mnu)); + /* 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; - /* Create new menu widget */ - GtkWidget *m = gtk_menu_new(); - gtk_widget_show(m); + /* Populate the combobox store */ GSList *sl = NULL; if ( gradient->hasStops() ) { for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { @@ -551,43 +562,33 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ } } if (!sl) { - GtkWidget *i = gtk_menu_item_new_with_label(_("No stops in gradient")); - gtk_widget_show(i); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); - gtk_widget_set_sensitive(mnu, FALSE); + 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); - GtkWidget *i = gtk_menu_item_new(); - gtk_widget_show(i); - g_object_set_data(G_OBJECT(i), "stop", stop); - GtkWidget *hb = gtk_hbox_new(FALSE, 4); - Gtk::Widget *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); - cpv->show(); - gtk_container_add( GTK_CONTAINER(hb), cpv->gobj() ); - g_object_set_data( G_OBJECT(i), "preview", cpv ); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - GtkWidget *l = gtk_label_new(repr->attribute("id")); - gtk_widget_show(l); - gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, 0); - gtk_widget_show(hb); - gtk_container_add(GTK_CONTAINER(i), hb); - gtk_menu_shell_append(GTK_MENU_SHELL(m), i); + 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(mnu, TRUE); + gtk_widget_set_sensitive(combo_box, TRUE); } - gtk_option_menu_set_menu(GTK_OPTION_MENU(mnu), m); /* Set history */ if (new_stop == NULL) { - gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), 0); + gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box) , 0); } else { - select_stop_in_list(mnu, gradient, new_stop); + select_stop_in_list(vb, gradient, new_stop); } blocked = FALSE; @@ -595,10 +596,9 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ // user selected existing stop from list -static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl) +static void sp_grad_edit_combo_box_changed (GtkComboBox *widget, GtkWidget *tbl) { - GObject *item = G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))); - SPStop *stop = SP_STOP(g_object_get_data(item, "stop")); + SPStop *stop = get_selected_stop(tbl); if (!stop) { return; } @@ -649,26 +649,36 @@ static void sp_grad_edit_select(GtkOptionMenu *mnu, GtkWidget *tbl) 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; - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - if ( g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop") ) { - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - + 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; } + + blocked = FALSE; } } @@ -687,11 +697,9 @@ 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); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - - SPStop *stop = static_cast<SPStop *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - if (stop == NULL) { + SPStop *stop = get_selected_stop(vb); + if (!stop) { return; } @@ -734,7 +742,7 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) sp_gradient_vector_widget_load_gradient(vb, gradient); Inkscape::GC::release(new_stop_repr); - update_stop_list(GTK_WIDGET(mnu), gradient, newstop); + 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); @@ -747,9 +755,11 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) { SPGradient *gradient = static_cast<SPGradient *>(g_object_get_data(G_OBJECT(vb), "gradient")); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(vb), "stopmenu")); - if (!g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")) return; - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + 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 @@ -769,7 +779,7 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) gradient->getRepr()->removeChild(stop->getRepr()); sp_gradient_vector_widget_load_gradient(vb, gradient); - update_stop_list(GTK_WIDGET(mnu), gradient, NULL); + update_stop_list(GTK_WIDGET(vb), gradient, NULL); DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Delete gradient stop")); } @@ -792,14 +802,27 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s sp_repr_add_listener(gradient->getRepr(), &grad_edit_dia_repr_events, vb); - /* Stop list */ - GtkWidget *mnu = gtk_option_menu_new(); - /* Create new menu widget */ - update_stop_list(GTK_WIDGET(mnu), gradient, NULL); - g_signal_connect(G_OBJECT(mnu), "changed", G_CALLBACK(sp_grad_edit_select), vb); - gtk_widget_show(mnu); - g_object_set_data(G_OBJECT(vb), "stopmenu", mnu); - gtk_box_pack_start(GTK_BOX(vb), mnu, FALSE, FALSE, 0); + /* 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 */ GtkWidget *hb = gtk_hbox_new(FALSE, 1); @@ -818,7 +841,6 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s gtk_widget_show(hb); gtk_box_pack_start(GTK_BOX(vb),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS); - /* Offset Slider and stuff */ hb = gtk_hbox_new(FALSE, 0); @@ -832,8 +854,12 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s 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); - GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(m)), "stop")); + + SPStop *stop = get_selected_stop(vb); + if (!stop) { + return NULL; + } + gtk_adjustment_set_value(Offset_adj, stop->offset); /* Slider */ @@ -883,7 +909,7 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s sp_gradient_vector_widget_load_gradient(vb, gradient); if (select_stop) { - select_stop_in_list(GTK_WIDGET(mnu), gradient, select_stop); + select_stop_in_list(GTK_WIDGET(vb), gradient, select_stop); } return vb; @@ -1018,8 +1044,10 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien gradient->ensureVector(); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(widget), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + 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")); @@ -1030,7 +1058,7 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien 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(mnu), gradient, NULL); + 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")) { @@ -1135,9 +1163,10 @@ static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *o ngr->ensureVector(); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); - + SPStop *stop = get_selected_stop(GTK_WIDGET(object)); + if (!stop) { + return; + } csel->base->getColorAlpha(stop->specified_color, stop->opacity); stop->currentColor = false; @@ -1170,8 +1199,10 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o /* We rely on normalized vector, i.e. stops HAVE to exist */ g_return_if_fail(ngr->getFirstStop() != NULL); - GtkOptionMenu *mnu = static_cast<GtkOptionMenu *>(g_object_get_data(G_OBJECT(object), "stopmenu")); - SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); + 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; @@ -1190,8 +1221,20 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o blocked = FALSE; - Inkscape::UI::Widget::ColorPreview *cpv = static_cast<Inkscape::UI::Widget::ColorPreview *>(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "preview")); - cpv->setRgba32(sp_stop_get_rgba32(stop)); + // 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); + } + } + } /* diff --git a/src/widgets/gradient-vector.h b/src/widgets/gradient-vector.h index b198895e7..f33240504 100644 --- a/src/widgets/gradient-vector.h +++ b/src/widgets/gradient-vector.h @@ -29,6 +29,7 @@ #define SP_IS_GRADIENT_VECTOR_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_GRADIENT_VECTOR_SELECTOR)) class SPDocument; +class SPObject; class SPGradient; class SPStop; @@ -42,13 +43,16 @@ struct SPGradientVectorSelector { SPDocument *doc; SPGradient *gr; - /* Vector menu */ - GtkWidget *menu; + /* ComboBox of gradient vectors */ + GtkWidget *combo_box; + GtkListStore *store; sigc::connection gradient_release_connection; sigc::connection defs_release_connection; sigc::connection defs_modified_connection; + gulong combo_connection; + void setSwatched(); }; @@ -71,6 +75,7 @@ SPGradient *sp_gradient_vector_selector_get_gradient (SPGradientVectorSelector * /* fixme: rethink this (Lauris) */ GtkWidget *sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop = NULL); +gchar *gr_prepare_label (SPObject *obj); #endif // SEEN_GRADIENT_VECTOR_H diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index d330e2bac..d67160483 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -267,11 +267,18 @@ sp_paint_selector_init(SPPaintSelector *psel) } /* Frame */ - psel->frame = gtk_frame_new(""); + psel->label = gtk_label_new(""); + GtkWidget *lbbox = gtk_hbox_new(FALSE, 4); + gtk_widget_show(psel->label); + gtk_box_pack_start(GTK_BOX(lbbox), psel->label, false, false, 4); + gtk_box_pack_start(GTK_BOX(psel), lbbox, false, false, 4); + + psel->frame = gtk_vbox_new(FALSE, 4); gtk_widget_show(psel->frame); - gtk_container_set_border_width(GTK_CONTAINER(psel->frame), 0); + //gtk_container_set_border_width(GTK_CONTAINER(psel->frame), 0); gtk_box_pack_start(GTK_BOX(psel), psel->frame, TRUE, TRUE, 0); + /* Last used color */ psel->color.set( 0.0, 0.0, 0.0 ); psel->alpha = 1.0; @@ -573,7 +580,7 @@ sp_paint_selector_set_mode_empty(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("No objects")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>No objects</b>")); } static void @@ -584,7 +591,7 @@ sp_paint_selector_set_mode_multiple(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Multiple styles")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Multiple styles</b>")); } static void @@ -595,7 +602,7 @@ sp_paint_selector_set_mode_unset(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Paint is undefined")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Paint is undefined</b>")); } static void @@ -606,7 +613,8 @@ sp_paint_selector_set_mode_none(SPPaintSelector *psel) sp_paint_selector_clear_frame(psel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("No paint")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>No paint</b>")); + } /* Color paint */ @@ -663,6 +671,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_paint_selector_color_changed), psel); /* Pack everything to frame */ gtk_container_add(GTK_CONTAINER(psel->frame), vb); + psel->selector = vb; /* Set color */ @@ -670,7 +679,8 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec } - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Flat color")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Flat color</b>")); + #ifdef SP_PS_VERBOSE g_print("Color req\n"); #endif @@ -733,10 +743,10 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe if (mode == SPPaintSelector::MODE_GRADIENT_LINEAR) { SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_LINEAR); //sp_gradient_selector_set_mode(SP_GRADIENT_SELECTOR(gsel), SP_GRADIENT_SELECTOR_MODE_LINEAR); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Linear gradient")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Linear gradient</b>")); } else { SP_GRADIENT_SELECTOR(gsel)->setMode(SPGradientSelector::MODE_RADIAL); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Radial gradient")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Radial gradient</b>")); } #ifdef SP_PS_VERBOSE g_print("Gradient req\n"); @@ -1016,7 +1026,7 @@ static void sp_paint_selector_set_mode_pattern(SPPaintSelector *psel, SPPaintSel psel->selector = tbl; g_object_set_data(G_OBJECT(psel->selector), "pattern-selector", tbl); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Pattern fill")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Pattern fill</b>")); } #ifdef SP_PS_VERBOSE g_print("Pattern req\n"); @@ -1091,7 +1101,7 @@ static void sp_paint_selector_set_mode_swatch(SPPaintSelector *psel, SPPaintSele psel->selector = GTK_WIDGET(swatchsel->gobj()); g_object_set_data(G_OBJECT(psel->selector), "swatch-selector", swatchsel); - gtk_frame_set_label(GTK_FRAME(psel->frame), _("Swatch fill")); + gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Swatch fill</b>")); } #ifdef SP_PS_VERBOSE diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index 69cfa602e..7400987ee 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -72,6 +72,7 @@ struct SPPaintSelector { GtkWidget *evenodd, *nonzero; GtkWidget *frame, *selector; + GtkWidget *label; SPColor color; float alpha; diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp new file mode 100644 index 000000000..a39ebf8be --- /dev/null +++ b/src/widgets/stroke-marker-selector.cpp @@ -0,0 +1,458 @@ +/** + * @file + * Combobox for selecting dash patterns - implementation. + */ +/* Author: + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Maximilian Albert <maximilian.albert@gmail.com> + * + * Copyright (C) 2002 Lauris Kaplinski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "stroke-marker-selector.h" + +#include <cstring> +#include <string> +#include <glibmm/i18n.h> +#include <2geom/coord.h> + + +#include "style.h" +#include "dialogs/dialog-events.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "preferences.h" +#include "path-prefix.h" +#include "io/sys.h" +#include "marker.h" +#include "sp-defs.h" +#include "sp-root.h" +#include "ui/cache/svg_preview_cache.h" +#include "helper/stock-items.h" + +#include <gtkmm/adjustment.h> +#include "ui/widget/spinbutton.h" + +static Inkscape::UI::Cache::SvgPreview svg_preview_cache; + +MarkerComboBox::MarkerComboBox(gchar const *id) : + Gtk::ComboBox(), + combo_id(id), + updating(false), + is_history(false) +{ + + marker_store = Gtk::ListStore::create(marker_columns); + set_model(marker_store); + pack_start(image_renderer, false); + pack_end(label_renderer, true); + label_renderer.set_padding(5, 0); + image_renderer.set_padding(5, 0); + set_cell_data_func(label_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareLabelRenderer)); + set_cell_data_func(image_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareImageRenderer)); + gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(gobj()), MarkerComboBox::separator_cb, NULL, NULL); + + empty_image = new Gtk::Image(); + + sandbox = ink_markers_preview_doc (); + desktop = inkscape_active_desktop(); + doc = sp_desktop_document(desktop); + + init_combo(); + + show(); +} + +MarkerComboBox::~MarkerComboBox() { + delete combo_id; + delete sandbox; +} + +/** + * Init the combobox widget to display markers from markers.svg + */ +void +MarkerComboBox::init_combo() +{ + updating = false; + + if (!doc) { + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = _("No document selected"); + row[marker_columns.image] = NULL; + set_sensitive(false); + set_current(NULL); + return; + } + + static SPDocument *markers_doc = NULL; + + // add "None" + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = _("None"); + row[marker_columns.marker] = g_strdup("none"); + row[marker_columns.image] = NULL; + + // find and load markers.svg + if (markers_doc == NULL) { + char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL); + if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) { + markers_doc = SPDocument::createNewDoc(markers_source, FALSE); + } + g_free(markers_source); + } + + // suck in from current doc + is_history = true; + sp_marker_list_from_doc(doc); + is_history = false; + + // add separator + Gtk::TreeModel::Row row_sep = *(marker_store->append()); + row_sep[marker_columns.label] = "Separator"; + row_sep[marker_columns.isseparator] = true; + row_sep[marker_columns.image] = NULL; + + // suck in from markers.svg + if (markers_doc) { + doc->ensureUpToDate(); + sp_marker_list_from_doc(markers_doc); + } + + set_sensitive(true); + + /* Set history */ + set_current(NULL); +} + +/** + * Sets the current marker in the marker combobox. + */ +void MarkerComboBox::set_current(SPObject *marker) +{ + updating = true; + + if (marker != NULL) { + bool mark_is_stock = false; + if (marker->getRepr()->attribute("inkscape:stockid")) { + mark_is_stock = true; + } + + gchar *markname = 0; + if (mark_is_stock) { + markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); + } else { + markname = g_strdup(marker->getRepr()->attribute("id")); + } + + set_selected(markname); + + g_free (markname); + } + else { + set_selected(NULL); + } + + updating = false; + +} +/** + * Return a uri string representing the current selected marker used for setting the marker style in the document + */ +const gchar * MarkerComboBox::get_active_marker_uri() +{ + /* Get Marker */ + const gchar *markid = get_active()->get_value(marker_columns.marker); + if (!markid) + { + return NULL; + } + + gchar const *marker = ""; + if (strcmp(markid, "none")) { + bool stockid = get_active()->get_value(marker_columns.isstock); + + gchar *markurn = g_strdup(markid); + if (stockid) markurn = g_strconcat("urn:inkscape:marker:",markid,NULL); + SPObject *mark = get_stock_item(markurn); + g_free(markurn); + if (mark) { + Inkscape::XML::Node *repr = mark->getRepr(); + marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); + } + } else { + marker = g_strdup(markid); + } + + return marker; +} + + +void MarkerComboBox::set_active_history() { + set_selected(get_active()->get_value(marker_columns.marker)); +} + + +void MarkerComboBox::set_selected(const gchar *name) { + + if (!name) { + set_active(0); + return; + } + + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.marker] && + !strcmp(row[marker_columns.marker], name)) { + set_active(iter); + if (strcmp(name, "none")) + set_history(row); + return; + } + } +} + +void MarkerComboBox::set_history(Gtk::TreeModel::Row match_row) { + + if (!match_row) { + return; + } + + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.history] && + !strcmp(row[marker_columns.marker], match_row[marker_columns.marker])) { + return; + } + } + + // Add a new row to the history + Gtk::TreeModel::Row row = *(marker_store->insert_after(marker_store->children().begin())); + row[marker_columns.marker] = g_strdup(match_row.get_value(marker_columns.marker)); + row[marker_columns.label] = match_row.get_value(marker_columns.label); + row[marker_columns.isstock] = match_row.get_value(marker_columns.isstock); + row[marker_columns.image] = match_row.get_value(marker_columns.image); + row[marker_columns.history] = true; +} + +/** + * Pick up all markers from source, except those that are in + * current_doc (if non-NULL), and add items to the combo. + */ +void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source) +{ + GSList *ml = get_marker_list(source); + GSList *clean_ml = NULL; + + for (; ml != NULL; ml = ml->next) { + if (!SP_IS_MARKER(ml->data)) + continue; + + // Add to the list of markers we really do wish to show + clean_ml = g_slist_prepend (clean_ml, ml->data); + } + add_markers(clean_ml, source); + + g_slist_free (ml); + g_slist_free (clean_ml); +} + +/** + * Returns a list of markers in the defs of the given source document as a GSList object + * Returns NULL if there are no markers in the document. + */ +GSList *MarkerComboBox::get_marker_list (SPDocument *source) +{ + if (source == NULL) + return NULL; + + GSList *ml = NULL; + SPDefs *defs = source->getDefs(); + for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) + { + if (SP_IS_MARKER(child)) { + ml = g_slist_prepend (ml, child); + } + } + return ml; +} + +/** + * Adds previews of markers in marker_list to the combo + */ +void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source) +{ + // Do this here, outside of loop, to speed up preview generation: + Inkscape::Drawing drawing; + unsigned const visionkey = SPItem::display_key_new(1); + drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); + + for (; marker_list != NULL; marker_list = marker_list->next) { + + Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); + bool isstock = (repr->attribute("inkscape:stockid")); + gchar const *markid = repr->attribute("id"); + + // generate preview + Gtk::Image *prv = create_marker_image (22, markid, source, drawing, visionkey); + prv->show(); + + Gtk::TreeModel::Row row = *(marker_store->append()); + row[marker_columns.label] = g_strdup(markid); + row[marker_columns.marker] = g_strdup(markid); + row[marker_columns.isstock] = isstock; + row[marker_columns.image] = prv; + row[marker_columns.history] = is_history; + + } + + sandbox->getRoot()->invoke_hide(visionkey); +} + +/** + * Creates a copy of the marker named mname, determines its visible and renderable + * area in the bounding box, and then renders it. This allows us to fill in + * preview images of each marker in the marker combobox. + */ +Gtk::Image * +MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, + SPDocument *source, Inkscape::Drawing &drawing, unsigned /*visionkey*/) +{ + // Retrieve the marker named 'mname' from the source SVG document + SPObject const *marker = source->getObjectById(mname); + if (marker == NULL) { + return NULL; + } + + // Create a copy repr of the marker with id="sample" + Inkscape::XML::Document *xml_doc = sandbox->getReprDoc(); + Inkscape::XML::Node *mrepr = marker->getRepr()->duplicate(xml_doc); + mrepr->setAttribute("id", "sample"); + + // Replace the old sample in the sandbox by the new one + Inkscape::XML::Node *defsrepr = sandbox->getObjectById("defs")->getRepr(); + SPObject *oldmarker = sandbox->getObjectById("sample"); + if (oldmarker) { + oldmarker->deleteObject(false); + } + + // TODO - This causes a SIGTRAP on windows + defsrepr->appendChild(mrepr); + + Inkscape::GC::release(mrepr); + +// Uncomment this to get the sandbox documents saved (useful for debugging) + //FILE *fp = fopen (g_strconcat(combo_id, mname, ".svg", NULL), "w"); + //sp_repr_save_stream(sandbox->getReprDoc(), fp); + //fclose (fp); + + // object to render; note that the id is the same as that of the combo we're building + SPObject *object = sandbox->getObjectById(combo_id); + sandbox->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + sandbox->ensureUpToDate(); + + if (object == NULL || !SP_IS_ITEM(object)) { + return NULL; // sandbox broken? + } + + SPItem *item = SP_ITEM(object); + // Find object's bbox in document + Geom::OptRect dbox = item->documentVisualBounds(); + + if (!dbox) { + return NULL; + } + + /* Update to renderable state */ + double sf = 0.8; + + gchar *cache_name = g_strconcat(combo_id, mname, NULL); + Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); + g_free (cache_name); + Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); + + if (!pixbuf) { + pixbuf = Glib::wrap(render_pixbuf(drawing, sf, *dbox, psize)); + svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); + } + + // Create widget + Gtk::Image *pb = new Gtk::Image(pixbuf); + + return pb; +} + +void MarkerComboBox::prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ) { + Glib::ustring name=(*row)[marker_columns.label]; + label_renderer.property_markup() = name.c_str(); +} + +void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ) { + + Gtk::Image *image = (*row)[marker_columns.image]; + if (image) + image_renderer.property_pixbuf() = image->get_pixbuf(); + else + image_renderer.property_pixbuf() = empty_image->get_pixbuf(); +} + +gboolean MarkerComboBox::separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { + + gboolean sep = FALSE; + gtk_tree_model_get(model, iter, 5, &sep, -1); + return sep; +} + +/** + * Returns a new document containing default start, mid, and end markers. + */ +SPDocument *MarkerComboBox::ink_markers_preview_doc () +{ +gchar const *buffer = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" +" <defs id=\"defs\" />" + +" <g id=\"marker-start\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:url(#sample);marker-mid:none;marker-end:none\"" +" d=\"M 12.5,13 L 25,13\" id=\"path1\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect2\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"0\" />" +" </g>" + +" <g id=\"marker-mid\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:url(#sample);marker-end:none\"" +" d=\"M 0,113 L 12.5,113 L 25,113\" id=\"path11\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect22\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"100\" />" +" </g>" + +" <g id=\"marker-end\">" +" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:none;marker-end:url(#sample)\"" +" d=\"M 0,213 L 12.5,213\" id=\"path111\" />" +" <rect style=\"fill:none;stroke:none\" id=\"rect222\"" +" width=\"25\" height=\"25\" x=\"0\" y=\"200\" />" +" </g>" + +"</svg>"; + + return SPDocument::createNewDocFromMem (buffer, strlen(buffer), FALSE); +} + +/* + 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 : diff --git a/src/widgets/stroke-marker-selector.h b/src/widgets/stroke-marker-selector.h new file mode 100644 index 000000000..4365b7e2a --- /dev/null +++ b/src/widgets/stroke-marker-selector.h @@ -0,0 +1,104 @@ +#ifndef SEEN_SP_MARKER_SELECTOR_NEW_H +#define SEEN_SP_MARKER_SELECTOR_NEW_H + +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Maximilian Albert <maximilian.albert> (gtkmm-ification) + * + * Copyright (C) 2002 Lauris Kaplinski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtkmm/box.h> +#include <gtkmm/combobox.h> +#include <gtkmm/liststore.h> + +#include <sigc++/signal.h> + +#include "document.h" +#include "inkscape.h" +#include "display/drawing.h" + +namespace Gtk { +class Container; +class Adjustment; +} + +/** + * ComboBox derived class for selecting stroke markers. + */ + +class MarkerComboBox : public Gtk::ComboBox { +public: + MarkerComboBox(gchar const *id); + ~MarkerComboBox(); + + sigc::signal<void> changed_signal; + + void set_current(SPObject *marker); + void set_active_history(); + void set_selected(const gchar *name); + const gchar *get_active_marker_uri(); + bool update() { return updating; }; + gchar const *get_id() { return combo_id; }; + +private: + + Glib::RefPtr<Gtk::ListStore> marker_store; + gchar const *combo_id; + bool updating; + bool is_history; + SPDesktop *desktop; + SPDocument *doc; + SPDocument *sandbox; + Gtk::Image *empty_image; + Gtk::CellRendererText label_renderer; + Gtk::CellRendererPixbuf image_renderer; + + class MarkerColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<Glib::ustring> label; + Gtk::TreeModelColumn<const gchar *> marker; // ustring doesnt work here on windows due to unicode + Gtk::TreeModelColumn<bool> isstock; + Gtk::TreeModelColumn<Gtk::Image *> image; + Gtk::TreeModelColumn<bool> history; + Gtk::TreeModelColumn<bool> isseparator; + + MarkerColumns() { + add(label); add(marker); add(isstock); add(image); add(history); add(isseparator); + } + }; + MarkerColumns marker_columns; + + void init_combo(); + void set_history(Gtk::TreeModel::Row match_row); + void sp_marker_list_from_doc(SPDocument *source); + GSList *get_marker_list (SPDocument *source); + void add_markers (GSList *marker_list, SPDocument *source); + SPDocument *ink_markers_preview_doc (); + Gtk::Image * create_marker_image(unsigned psize, gchar const *mname, + SPDocument *source, Inkscape::Drawing &drawing, unsigned /*visionkey*/); + + /* + * Callbacks for drawing the combo box + */ + void prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ); + void prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ); + static gboolean separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); + + +}; + +#endif // SEEN_SP_MARKER_SELECTOR_NEW_H + +/* + 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 : diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index a49a26734..f6afec18e 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -55,27 +55,25 @@ #include "xml/repr.h" #include "stroke-style.h" +#include "stroke-marker-selector.h" #include "fill-style.h" // to get sp_fill_style_widget_set_desktop #include "fill-n-stroke-factory.h" -#include <gtkmm/optionmenu.h> #include "verbs.h" using Inkscape::DocumentUndo; -/** Marker selection option menus */ -static Gtk::OptionMenu * marker_start_menu = NULL; -static Gtk::OptionMenu * marker_mid_menu = NULL; -static Gtk::OptionMenu * marker_end_menu = NULL; -sigc::connection marker_start_menu_connection; -sigc::connection marker_mid_menu_connection; -sigc::connection marker_end_menu_connection; +static MarkerComboBox *start_marker_combobox = NULL; +static MarkerComboBox *mid_marker_combobox = NULL; +static MarkerComboBox *end_marker_combobox = NULL; -static SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); -static void ink_markers_menu_update(Gtk::Container* spw, SPMarkerLoc const which); +sigc::connection start_marker_connection; +sigc::connection mid_marker_connection; +sigc::connection end_marker_connection; -static Inkscape::UI::Cache::SvgPreview svg_preview_cache; +static SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); +static void ink_markers_combo_update(Gtk::Container* spw, SPMarkerLoc const which); Gtk::Widget *sp_stroke_style_paint_widget_new(void) { @@ -87,8 +85,6 @@ void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop) sp_fill_style_widget_set_desktop(widget, desktop); } - - /* Line */ static void sp_stroke_style_line_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data); @@ -105,7 +101,7 @@ static void sp_stroke_style_miterlimit_changed(Gtk::Container *spw); static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *spw); static void sp_stroke_style_line_dash_changed(Gtk::Container *spw); -static void sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects); +static void sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects); /** @@ -145,303 +141,12 @@ sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, } /** - * Create sa copy of the marker named mname, determines its visible and renderable - * area in menu_id's bounding box, and then renders it. This allows us to fill in - * preview images of each marker in the marker menu. - */ -static Gtk::Image * -sp_marker_prev_new(unsigned psize, gchar const *mname, - SPDocument *source, SPDocument *sandbox, - gchar const *menu_id, Inkscape::Drawing &drawing, unsigned /*visionkey*/) -{ - // Retrieve the marker named 'mname' from the source SVG document - SPObject const *marker = source->getObjectById(mname); - if (marker == NULL) { - return NULL; - } - - // Create a copy repr of the marker with id="sample" - Inkscape::XML::Document *xml_doc = sandbox->getReprDoc(); - Inkscape::XML::Node *mrepr = marker->getRepr()->duplicate(xml_doc); - mrepr->setAttribute("id", "sample"); - - // Replace the old sample in the sandbox by the new one - Inkscape::XML::Node *defsrepr = sandbox->getObjectById("defs")->getRepr(); - SPObject *oldmarker = sandbox->getObjectById("sample"); - if (oldmarker) { - oldmarker->deleteObject(false); - } - defsrepr->appendChild(mrepr); - Inkscape::GC::release(mrepr); - -// Uncomment this to get the sandbox documents saved (useful for debugging) - //FILE *fp = fopen (g_strconcat(menu_id, mname, ".svg", NULL), "w"); - //sp_repr_save_stream(sandbox->getReprDoc(), fp); - //fclose (fp); - - // object to render; note that the id is the same as that of the menu we're building - SPObject *object = sandbox->getObjectById(menu_id); - sandbox->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - sandbox->ensureUpToDate(); - - if (object == NULL || !SP_IS_ITEM(object)) { - return NULL; // sandbox broken? - } - - SPItem *item = SP_ITEM(object); - // Find object's bbox in document - Geom::OptRect dbox = item->documentVisualBounds(); - - if (!dbox) { - return NULL; - } - - /* Update to renderable state */ - double sf = 0.8; - - gchar *cache_name = g_strconcat(menu_id, mname, NULL); - Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); - g_free (cache_name); - // TODO: is this correct? - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); - - if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(drawing, sf, *dbox, psize)); - svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); - } - - // Create widget - Gtk::Image *pb = new Gtk::Image(pixbuf); - - return pb; -} - -/** - * Returns a list of markers in the defs of the given source document as a GSList object - * Returns NULL if there are no markers in the document. - */ -GSList * -ink_marker_list_get (SPDocument *source) -{ - if (source == NULL) - return NULL; - - GSList *ml = NULL; - SPDefs *defs = source->getDefs(); - for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) - { - if (SP_IS_MARKER(child)) { - ml = g_slist_prepend (ml, child); - } - } - return ml; -} - -#define MARKER_ITEM_MARGIN 0 - -/** - * Adds previews of markers in marker_list to the given menu widget - */ -static void -sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPDocument *sandbox, gchar const *menu_id) -{ - // Do this here, outside of loop, to speed up preview generation: - Inkscape::Drawing drawing; - unsigned const visionkey = SPItem::display_key_new(1); - drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); - - for (; marker_list != NULL; marker_list = marker_list->next) { - Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); - Gtk::MenuItem *i = new Gtk::MenuItem(); - i->show(); - - if (repr->attribute("inkscape:stockid")) { - i->set_data("stockid", (void *) "true"); - } else { - i->set_data("stockid", (void *) "false"); - } - - gchar const *markid = repr->attribute("id"); - i->set_data("marker", (void *) markid); - - Gtk::HBox *hb = new Gtk::HBox(false, MARKER_ITEM_MARGIN); - hb->show(); - - // generate preview - - Gtk::Image *prv = sp_marker_prev_new (22, markid, source, sandbox, menu_id, drawing, visionkey); - prv->show(); - hb->pack_start(*prv, false, false, 6); - - // create label - Gtk::Label *l = new Gtk::Label(repr->attribute("id")); - l->show(); - l->set_alignment(0.0, 0.5); - - hb->pack_start(*l, true, true, 0); - - hb->show(); - i->add(*hb); - - m->append(*i); - } - - sandbox->getRoot()->invoke_hide(visionkey); -} - -/** - * Pick up all markers from source, except those that are in - * current_doc (if non-NULL), and add items to the m menu. - */ -static void sp_marker_list_from_doc(Gtk::Menu *m, SPDocument * /*current_doc*/, SPDocument *source, SPDocument * /*markers_doc*/, SPDocument *sandbox, gchar const *menu_id) -{ - GSList *ml = ink_marker_list_get(source); - GSList *clean_ml = NULL; - - for (; ml != NULL; ml = ml->next) { - if (!SP_IS_MARKER(ml->data)) - continue; - - // Add to the list of markers we really do wish to show - clean_ml = g_slist_prepend (clean_ml, ml->data); - } - sp_marker_menu_build(m, clean_ml, source, sandbox, menu_id); - - g_slist_free (ml); - g_slist_free (clean_ml); -} - -/** - * Returns a new document containing default start, mid, and end markers. - */ -SPDocument * -ink_markers_preview_doc () -{ -gchar const *buffer = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" -" <defs id=\"defs\" />" - -" <g id=\"marker-start\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:url(#sample);marker-mid:none;marker-end:none\"" -" d=\"M 12.5,13 L 25,13\" id=\"path1\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect2\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"0\" />" -" </g>" - -" <g id=\"marker-mid\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:url(#sample);marker-end:none\"" -" d=\"M 0,113 L 12.5,113 L 25,113\" id=\"path11\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect22\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"100\" />" -" </g>" - -" <g id=\"marker-end\">" -" <path style=\"fill:none;stroke:black;stroke-width:1.7;marker-start:none;marker-mid:none;marker-end:url(#sample)\"" -" d=\"M 0,213 L 12.5,213\" id=\"path111\" />" -" <rect style=\"fill:none;stroke:none\" id=\"rect222\"" -" width=\"25\" height=\"25\" x=\"0\" y=\"200\" />" -" </g>" - -"</svg>"; - - return SPDocument::createNewDocFromMem (buffer, strlen(buffer), FALSE); -} - -static void -ink_marker_menu_create_menu(Gtk::Menu *m, gchar const *menu_id, SPDocument *doc, SPDocument *sandbox) -{ - static SPDocument *markers_doc = NULL; - - // add "None" - Gtk::MenuItem *i = new Gtk::MenuItem(); - i->show(); - - i->set_data("marker", (void *) "none"); - - Gtk::HBox *hb = new Gtk::HBox(false, MARKER_ITEM_MARGIN); - hb->show(); - - Gtk::Label *l = new Gtk::Label( _("None") ); - l->show(); - l->set_alignment(0.0, 0.5); - - hb->pack_start(*l, true, true, 0); - - hb->show(); - i->add(*hb); - m->append(*i); - - // find and load markers.svg - if (markers_doc == NULL) { - char *markers_source = g_build_filename(INKSCAPE_MARKERSDIR, "markers.svg", NULL); - if (Inkscape::IO::file_test(markers_source, G_FILE_TEST_IS_REGULAR)) { - markers_doc = SPDocument::createNewDoc(markers_source, FALSE); - } - g_free(markers_source); - } - - // suck in from current doc - sp_marker_list_from_doc(m, NULL, doc, markers_doc, sandbox, menu_id); - - // add separator - { - //Gtk::Separator *i = gtk_separator_menu_item_new(); - Gtk::SeparatorMenuItem *i = new Gtk::SeparatorMenuItem(); - i->show(); - m->append(*i); - } - - // suck in from markers.svg - if (markers_doc) { - doc->ensureUpToDate(); - sp_marker_list_from_doc(m, doc, markers_doc, NULL, sandbox, menu_id); - } - -} - -/** - * Creates a menu widget to display markers from markers.svg - */ -static Gtk::OptionMenu * -ink_marker_menu(Gtk::Widget * /*tbl*/, gchar const *menu_id, SPDocument *sandbox) -{ - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *doc = sp_desktop_document(desktop); - Gtk::OptionMenu *mnu = new Gtk::OptionMenu(); - - /* Create new menu widget */ - Gtk::Menu *m = new Gtk::Menu(); - m->show(); - - mnu->set_data("updating", (gpointer) FALSE); - - if (!doc) { - Gtk::MenuItem *i = new Gtk::MenuItem(_("No document selected")); - i->show(); - m->append(*i); - mnu->set_sensitive(false); - - } else { - ink_marker_menu_create_menu(m, menu_id, doc, sandbox); - - mnu->set_sensitive(true); - } - - mnu->set_data("menu_id", const_cast<gchar *>(menu_id)); - mnu->set_menu(*m); - - /* Set history */ - mnu->set_history(0); - - return mnu; -} - -/** - * Handles when user selects one of the markers from the marker menu. - * Defines a uri string to refer to it, then applies it to all selected + * Handles when user selects one of the markers from the marker combobox. + * Gets the marker uri string and applies it to all selected * items in the current desktop. */ static void -sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const which) +sp_marker_select(MarkerComboBox *marker_combo, Gtk::Container *spw, SPMarkerLoc const which) { if (spw->get_data("update")) { return; @@ -454,33 +159,17 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh } /* Get Marker */ - if (!mnu->get_menu()->get_active()->get_data("marker")) - { - return; - } - gchar *markid = static_cast<gchar *>(mnu->get_menu()->get_active()->get_data("marker")); - gchar const *marker = ""; - if (strcmp(markid, "none")) { - gchar *stockid = static_cast<gchar *>(mnu->get_menu()->get_active()->get_data("stockid")); - - gchar *markurn = markid; - if (!strcmp(stockid,"true")) markurn = g_strconcat("urn:inkscape:marker:",markid,NULL); - SPObject *mark = get_stock_item(markurn); - if (mark) { - Inkscape::XML::Node *repr = mark->getRepr(); - marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); - } - } else { - marker = markid; - } + gchar const *marker = marker_combo->get_active_marker_uri(); + + SPCSSAttr *css = sp_repr_css_attr_new(); - gchar const *menu_id = static_cast<gchar const *>(mnu->get_data("menu_id")); - sp_repr_css_set_property(css, menu_id, marker); + gchar const *combo_id = marker_combo->get_id(); + sp_repr_css_set_property(css, combo_id, marker); - // Also update the marker dropdown menus, so the document's markers - // show up at the top of the menu + // Also update the marker combobox, so the document's markers + // show up at the top of the combobox // sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); - ink_markers_menu_update(spw, which); + ink_markers_combo_update(spw, which); Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); @@ -505,72 +194,26 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh }; -static unsigned int -ink_marker_menu_get_pos(Gtk::Menu *mnu, gchar const *markname) -{ - if (markname == NULL) - markname = static_cast<gchar const *>(mnu->get_active()->get_data("marker")); - - if (markname == NULL) - return 0; - - std::vector<Gtk::Widget *> kids = mnu->get_children(); - unsigned int i = 0; - for (; i < kids.size();) { - gchar const *mark = static_cast<gchar const *>(kids[i]->get_data("marker")); - if (mark && strcmp(mark, markname) == 0) { - break; - } - ++i; - } - - return i; -} - static void -ink_markers_menu_update(Gtk::Container* /*spw*/, SPMarkerLoc const which) { - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *document = sp_desktop_document(desktop); - SPDocument *sandbox = ink_markers_preview_doc (); - Gtk::Menu *m; - int pos; +ink_markers_combo_update(Gtk::Container* /*spw*/, SPMarkerLoc const which) { - // TODO: this code can be shortened by abstracting out marker_(start|mid|end)_... switch (which) { case SP_MARKER_LOC_START: - marker_start_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_start_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-start", document, sandbox); - marker_start_menu->remove_menu(); - marker_start_menu->set_menu(*m); - marker_start_menu->set_history(pos); - marker_start_menu_connection.unblock(); + start_marker_connection.block(); + start_marker_combobox->set_active_history(); + start_marker_connection.unblock(); break; case SP_MARKER_LOC_MID: - marker_mid_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_mid_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-mid", document, sandbox); - marker_mid_menu->remove_menu(); - marker_mid_menu->set_menu(*m); - marker_mid_menu->set_history(pos); - marker_mid_menu_connection.unblock(); + mid_marker_connection.block(); + mid_marker_combobox->set_active_history(); + mid_marker_connection.unblock(); break; case SP_MARKER_LOC_END: - marker_end_menu_connection.block(); - pos = ink_marker_menu_get_pos(marker_end_menu->get_menu(), NULL); - m = new Gtk::Menu(); - m->show(); - ink_marker_menu_create_menu(m, "marker-end", document, sandbox); - marker_end_menu->remove_menu(); - marker_end_menu->set_menu(*m); - marker_end_menu->set_history(pos); - marker_end_menu_connection.unblock(); + end_marker_connection.block(); + end_marker_combobox->set_active_history(); + end_marker_connection.unblock(); break; default: g_assert_not_reached(); @@ -675,7 +318,7 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) // TODO: when this is gtkmmified, use an Inkscape::UI::Widget::ScalarUnit instead of the separate // spinbutton and unit selector for stroke width. In sp_stroke_style_line_update, use -// setHundredPercent to remember the aeraged width corresponding to 100%. Then the +// setHundredPercent to remember the averaged width corresponding to 100%. Then the // stroke_width_set_unit will be removed (because ScalarUnit takes care of conversions itself), and // with it, the two remaining calls of stroke_average_width, allowing us to get rid of that // function in desktop-style. @@ -822,48 +465,40 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) i++; /* Drop down marker selectors*/ - // TODO: this code can be shortened by iterating over the possible menus! - - // doing this here once, instead of for each preview, to speed things up - SPDocument *sandbox = ink_markers_preview_doc (); - // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path. - //spw_label(t, _("_Start Markers:"), 0, i); - marker_start_menu = ink_marker_menu(spw ,"marker-start", sandbox); - spw_label(t, _("_Start Markers:"), 0, i, marker_start_menu); - marker_start_menu->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); - marker_start_menu_connection = marker_start_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_start_menu, spw, SP_MARKER_LOC_START)); - marker_start_menu->show(); - t->attach(*marker_start_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("start_mark_menu", marker_start_menu); + start_marker_combobox = manage(new MarkerComboBox("marker-start")); + spw_label(t, _("_Start Markers:"), 0, i, start_marker_combobox); + start_marker_combobox->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); + start_marker_connection = start_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), start_marker_combobox, spw, SP_MARKER_LOC_START)); + start_marker_combobox->show(); + t->attach(*start_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("start_marker_combobox", start_marker_combobox); i++; - //spw_label(t, _("_Mid Markers:"), 0, i); - marker_mid_menu = ink_marker_menu(spw ,"marker-mid", sandbox); - spw_label(t, _("_Mid Markers:"), 0, i, marker_mid_menu); - marker_mid_menu->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); - marker_mid_menu_connection = marker_mid_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_mid_menu,spw, SP_MARKER_LOC_MID)); - marker_mid_menu->show(); - t->attach(*marker_mid_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("mid_mark_menu", marker_mid_menu); + mid_marker_combobox = manage(new MarkerComboBox("marker-mid")); + spw_label(t, _("_Mid Markers:"), 0, i, mid_marker_combobox); + mid_marker_combobox->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); + mid_marker_connection = mid_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), mid_marker_combobox, spw, SP_MARKER_LOC_MID)); + mid_marker_combobox->show(); + t->attach(*mid_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("mid_marker_combobox", mid_marker_combobox); i++; - //spw_label(t, _("_End Markers:"), 0, i); - marker_end_menu = ink_marker_menu(spw ,"marker-end", sandbox); - spw_label(t, _("_End Markers:"), 0, i, marker_end_menu); - marker_end_menu->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); - marker_end_menu_connection = marker_end_menu->signal_changed().connect( - sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), marker_end_menu, spw, SP_MARKER_LOC_END)); - marker_end_menu->show(); - t->attach(*marker_end_menu, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("end_mark_menu", marker_end_menu); + end_marker_combobox = manage(new MarkerComboBox("marker-end")); + spw_label(t, _("_End Markers:"), 0, i, end_marker_combobox); + end_marker_combobox->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); + end_marker_connection = end_marker_combobox->signal_changed().connect( + sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( + sigc::ptr_fun(&sp_marker_select), end_marker_combobox, spw, SP_MARKER_LOC_END)); + end_marker_combobox->show(); + t->attach(*end_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("end_marker_combobox", end_marker_combobox); i++; // FIXME: we cheat and still use gtk+ signals @@ -1090,7 +725,7 @@ sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) SPStyle * const style = object->style; /* Markers */ - sp_stroke_style_update_marker_menus(spw, objects); // FIXME: make this desktop query too + sp_stroke_style_update_marker_combo(spw, objects); // FIXME: make this desktop query too /* Dash */ sp_dash_selector_set_from_style(dsel, style); // FIXME: make this desktop query too @@ -1270,6 +905,7 @@ static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *s return; } + if (tb->get_active()) { gchar const *join @@ -1346,50 +982,18 @@ sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) tb->set_active(active == tb); } -/** - * Sets the current marker in the marker menu. - */ -static void -ink_marker_menu_set_current(SPObject *marker, Gtk::OptionMenu *mnu) -{ - mnu->set_data("update", GINT_TO_POINTER(TRUE)); - - Gtk::Menu *m = mnu->get_menu(); - if (marker != NULL) { - bool mark_is_stock = false; - if (marker->getRepr()->attribute("inkscape:stockid")) { - mark_is_stock = true; - } - - gchar *markname = 0; - if (mark_is_stock) { - markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); - } else { - markname = g_strdup(marker->getRepr()->attribute("id")); - } - - int markpos = ink_marker_menu_get_pos(m, markname); - mnu->set_history(markpos); - - g_free (markname); - } - else { - mnu->set_history(0); - } - mnu->set_data("update", GINT_TO_POINTER(FALSE)); -} /** - * Updates the marker menus to highlight the appropriate marker and scroll to + * Updates the marker combobox to highlight the appropriate marker and scroll to * that marker. */ static void -sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) +sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) { struct { char const *key; int loc; } const keyloc[] = { - { "start_mark_menu", SP_MARKER_LOC_START }, - { "mid_mark_menu", SP_MARKER_LOC_MID }, - { "end_mark_menu", SP_MARKER_LOC_END } + { "start_marker_combobox", SP_MARKER_LOC_START }, + { "mid_marker_combobox", SP_MARKER_LOC_MID }, + { "end_marker_combobox", SP_MARKER_LOC_END } }; bool all_texts = true; @@ -1400,9 +1004,9 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) } for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { - Gtk::OptionMenu *mnu = static_cast<Gtk::OptionMenu *>(spw->get_data(keyloc[i].key)); - // Per SVG spec, text objects cannot have markers; disable menus if only texts are selected - mnu->set_sensitive(!all_texts); + MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); + // Per SVG spec, text objects cannot have markers; disable combobox if only texts are selected + combo->set_sensitive(!all_texts); } // We show markers of the first object in the list only @@ -1412,11 +1016,11 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { // For all three marker types, - // find the corresponding menu - Gtk::OptionMenu *mnu = static_cast<Gtk::OptionMenu *>(spw->get_data(keyloc[i].key)); + // find the corresponding combobox item + MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); // Quit if we're in update state - if (mnu->get_data("update")) { + if (combo->update()) { return; } @@ -1425,13 +1029,14 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) // Extract the name of the marker that the object uses SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, object->document); - // Scroll the menu to that marker - ink_marker_menu_set_current(marker, mnu); + // Scroll the combobox to that marker + combo->set_current(marker); } else { - mnu->set_history(0); + combo->set_current(NULL); } } + } |
