summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorValentin Ionita <valentin.ionita1201@gmail.com>2019-08-19 18:38:08 +0000
committerTavmjong Bah <tavmjong@free.fr>2019-08-19 18:38:08 +0000
commitdaf25233fe9b7713f0b5c3c6f1b42b3fac8abb1c (patch)
tree2143be1f81e30ef55be7a548bebe6734c3533248 /src
parentreduce usage of desktop coordinates (#341) (diff)
downloadinkscape-daf25233fe9b7713f0b5c3c6f1b42b3fac8abb1c.tar.gz
inkscape-daf25233fe9b7713f0b5c3c6f1b42b3fac8abb1c.zip
Add paint server dialog. Currently handles patterns and hatches. GSOC 2019.
Diffstat (limited to 'src')
-rw-r--r--src/desktop.cpp22
-rw-r--r--src/helper/stock-items.cpp49
-rw-r--r--src/io/resource.cpp13
-rw-r--r--src/io/resource.h3
-rw-r--r--src/path-prefix.h18
-rw-r--r--src/ui/CMakeLists.txt4
-rw-r--r--src/ui/dialog/dialog-manager.cpp5
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp11
-rw-r--r--src/ui/dialog/inkscape-preferences.h4
-rw-r--r--src/ui/dialog/paint-servers.cpp537
-rw-r--r--src/ui/dialog/paint-servers.h90
-rw-r--r--src/verbs.cpp7
-rw-r--r--src/verbs.h1
-rw-r--r--src/widgets/paint-selector.cpp31
-rw-r--r--src/widgets/paint-selector.h1
15 files changed, 730 insertions, 66 deletions
diff --git a/src/desktop.cpp b/src/desktop.cpp
index 650878968..fa9f6d6d3 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -949,14 +949,14 @@ Geom::Rect SPDesktop::get_display_area(bool use_integer_viewbox) const
void
SPDesktop::zoom_absolute_keep_point (Geom::Point const &c, double zoom)
{
- zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
+ zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
Geom::Point w = d2w( c ); // Must be before zoom changed.
_current_affine.setScale( Geom::Scale(zoom, yaxisdir() * zoom) );
set_display_area( c, w );
}
-void
+void
SPDesktop::zoom_relative_keep_point (Geom::Point const &c, double zoom)
{
double new_zoom = _current_affine.getZoom() * zoom;
@@ -967,7 +967,7 @@ SPDesktop::zoom_relative_keep_point (Geom::Point const &c, double zoom)
/**
* Zoom aligning the point 'c' to the center of desktop window.
*/
-void
+void
SPDesktop::zoom_absolute_center_point (Geom::Point const &c, double zoom)
{
zoom = CLAMP (zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
@@ -977,7 +977,7 @@ SPDesktop::zoom_absolute_center_point (Geom::Point const &c, double zoom)
}
-void
+void
SPDesktop::zoom_relative_center_point (Geom::Point const &c, double zoom)
{
double new_zoom = _current_affine.getZoom() * zoom;
@@ -1064,7 +1064,7 @@ SPDesktop::zoom_selection()
*/
void SPDesktop::zoom_center_page()
{
- zoom_absolute_center_point(Geom::Point(doc()->getWidth().value("px")/2, doc()->getHeight().value("px")/2), this->current_zoom());
+ zoom_absolute_center_point(Geom::Point(doc()->getWidth().value("px")/2, doc()->getHeight().value("px")/2), this->current_zoom());
}
@@ -1144,7 +1144,7 @@ SPDesktop::rotate_absolute_keep_point (Geom::Point const &c, double rotate)
}
-void
+void
SPDesktop::rotate_relative_keep_point (Geom::Point const &c, double rotate)
{
Geom::Point w = d2w( c ); // Must be before rotate changed.
@@ -1156,7 +1156,7 @@ SPDesktop::rotate_relative_keep_point (Geom::Point const &c, double rotate)
/**
* Rotate aligning the point 'c' to the center of desktop window.
*/
-void
+void
SPDesktop::rotate_absolute_center_point (Geom::Point const &c, double rotate)
{
_current_affine.setRotate( rotate );
@@ -1165,7 +1165,7 @@ SPDesktop::rotate_absolute_center_point (Geom::Point const &c, double rotate)
}
-void
+void
SPDesktop::rotate_relative_center_point (Geom::Point const &c, double rotate)
{
_current_affine.addRotate( rotate );
@@ -1198,7 +1198,7 @@ SPDesktop::flip_relative_keep_point (Geom::Point const &c, CanvasFlip flip)
/**
* Flip aligning the point 'c' to the center of desktop window.
*/
-void
+void
SPDesktop::flip_absolute_center_point (Geom::Point const &c, CanvasFlip flip)
{
_current_affine.setFlip( flip );
@@ -1207,7 +1207,7 @@ SPDesktop::flip_absolute_center_point (Geom::Point const &c, CanvasFlip flip)
}
-void
+void
SPDesktop::flip_relative_center_point (Geom::Point const &c, CanvasFlip flip)
{
_current_affine.addFlip( flip );
@@ -2059,6 +2059,7 @@ SPDesktop::show_dialogs()
mapVerbPreference.insert(std::make_pair ("ObjectProperties", "/dialogs/object") );
mapVerbPreference.insert(std::make_pair ("SpellCheck", "/dialogs/spellcheck") );
mapVerbPreference.insert(std::make_pair ("Symbols", "/dialogs/symbols") );
+ mapVerbPreference.insert(std::make_pair ("PaintServers", "/dialogs/paint") );
mapVerbPreference.insert(std::make_pair ("ObjectsPanel", "/dialogs/objects") );
mapVerbPreference.insert(std::make_pair ("Prototype", "/dialogs/prototype") );
@@ -2119,4 +2120,3 @@ SPDesktop::show_dialogs()
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
-
diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp
index 6ee6d832f..ca96d6b4a 100644
--- a/src/helper/stock-items.cpp
+++ b/src/helper/stock-items.cpp
@@ -38,7 +38,7 @@ static SPObject *sp_gradient_load_from_svg(gchar const *name, SPDocument *curren
// FIXME: these should be merged with the icon loading code so they
-// can share a common file/doc cache. This function should just
+// can share a common file/doc cache. This function should just
// take the dir to look in, and the file to check for, and cache
// against that, rather than the existing copy/paste code seen here.
@@ -89,21 +89,21 @@ sp_pattern_load_from_svg(gchar const *name, SPDocument *current_doc)
}
/* Try to load from document */
if (!edoc && !doc) {
- gchar *patterns = g_build_filename(INKSCAPE_PATTERNSDIR, "/patterns.svg", NULL);
+ gchar *patterns = g_build_filename(INKSCAPE_PAINTDIR, "/patterns.svg", NULL);
if (Inkscape::IO::file_test(patterns, G_FILE_TEST_IS_REGULAR)) {
doc = SPDocument::createNewDoc(patterns, FALSE);
}
if (!doc) {
- gchar *patterns = g_build_filename(CREATE_PATTERNSDIR, "/patterns.svg", NULL);
- if (Inkscape::IO::file_test(patterns, G_FILE_TEST_IS_REGULAR)) {
- doc = SPDocument::createNewDoc(patterns, FALSE);
- }
- g_free(patterns);
- if (doc) {
- doc->ensureUpToDate();
- } else {
- edoc = TRUE;
- }
+ gchar *patterns = g_build_filename(CREATE_PAINTDIR, "/patterns.svg", NULL);
+ if (Inkscape::IO::file_test(patterns, G_FILE_TEST_IS_REGULAR)) {
+ doc = SPDocument::createNewDoc(patterns, FALSE);
+ }
+ g_free(patterns);
+ if (doc) {
+ doc->ensureUpToDate();
+ } else {
+ edoc = TRUE;
+ }
}
}
if (!edoc && doc) {
@@ -132,12 +132,12 @@ sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
}
/* Try to load from document */
if (!edoc && !doc) {
- gchar *gradients = g_build_filename(INKSCAPE_GRADIENTSDIR, "/gradients.svg", NULL);
+ gchar *gradients = g_build_filename(INKSCAPE_PAINTDIR, "/gradients.svg", NULL);
if (Inkscape::IO::file_test(gradients, G_FILE_TEST_IS_REGULAR)) {
doc = SPDocument::createNewDoc(gradients, FALSE);
}
if (!doc) {
- gchar *gradients = g_build_filename(CREATE_GRADIENTSDIR, "/gradients.svg", NULL);
+ gchar *gradients = g_build_filename(CREATE_PAINTDIR, "/gradients.svg", NULL);
if (Inkscape::IO::file_test(gradients, G_FILE_TEST_IS_REGULAR)) {
doc = SPDocument::createNewDoc(gradients, FALSE);
}
@@ -171,7 +171,7 @@ sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc)
SPObject *get_stock_item(gchar const *urn, gboolean stock)
{
g_assert(urn != nullptr);
-
+
/* check its an inkscape URN */
if (!strncmp (urn, "urn:inkscape:", 13)) {
@@ -183,11 +183,11 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock)
name_p++;
a++;
}
-
+
if (*name_p ==':') {
name_p++;
}
-
+
gchar * base = g_strndup(e, a);
SPDocument *doc = SP_ACTIVE_DOCUMENT;
@@ -207,7 +207,6 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock)
object = &child;
}
}
-
}
else if (!strcmp(base,"pattern") && !stock) {
for (auto& child: defs->children)
@@ -219,7 +218,6 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock)
object = &child;
}
}
-
}
else if (!strcmp(base,"gradient") && !stock) {
for (auto& child: defs->children)
@@ -231,11 +229,10 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock)
object = &child;
}
}
-
}
-
+
if (object == nullptr) {
-
+
if (!strcmp(base, "marker")) {
object = sp_marker_load_from_svg(name_p, doc);
}
@@ -246,19 +243,19 @@ SPObject *get_stock_item(gchar const *urn, gboolean stock)
object = sp_gradient_load_from_svg(name_p, doc);
}
}
-
+
g_free(base);
g_free(name);
-
+
if (object) {
object->setAttribute("inkscape:isstock", "true");
}
return object;
}
-
+
else {
-
+
SPDocument *doc = SP_ACTIVE_DOCUMENT;
SPObject *object = doc->getObjectById(urn);
diff --git a/src/io/resource.cpp b/src/io/resource.cpp
index 9f0f0a4ae..a57d188e7 100644
--- a/src/io/resource.cpp
+++ b/src/io/resource.cpp
@@ -47,13 +47,12 @@ gchar *_get_path(Domain domain, Type type, char const *filename)
case EXTENSIONS: temp = INKSCAPE_EXTENSIONDIR; break;
case FILTERS: temp = INKSCAPE_FILTERDIR; break;
case FONTS: temp = INKSCAPE_FONTSDIR; break;
- case GRADIENTS: temp = INKSCAPE_GRADIENTSDIR; break;
case ICONS: temp = INKSCAPE_ICONSDIR; break;
case KEYS: temp = INKSCAPE_KEYSDIR; break;
case MARKERS: temp = INKSCAPE_MARKERSDIR; break;
case NONE: g_assert_not_reached(); break;
+ case PAINT: temp = INKSCAPE_PAINTDIR; break;
case PALETTES: temp = INKSCAPE_PALETTESDIR; break;
- case PATTERNS: temp = INKSCAPE_PATTERNSDIR; break;
case SCREENS: temp = INKSCAPE_SCREENSDIR; break;
case SYMBOLS: temp = INKSCAPE_SYMBOLSDIR; break;
case TEMPLATES: temp = INKSCAPE_TEMPLATESDIR; break;
@@ -68,9 +67,8 @@ gchar *_get_path(Domain domain, Type type, char const *filename)
case CREATE: {
gchar const* temp = nullptr;
switch (type) {
- case GRADIENTS: temp = CREATE_GRADIENTSDIR; break;
+ case PAINT: temp = CREATE_PAINTDIR; break;
case PALETTES: temp = CREATE_PALETTESDIR; break;
- case PATTERNS: temp = CREATE_PATTERNSDIR; break;
default: temp = "";
}
path = g_strdup(temp);
@@ -84,13 +82,12 @@ gchar *_get_path(Domain domain, Type type, char const *filename)
case EXTENSIONS: name = "extensions"; break;
case FILTERS: name = "filters"; break;
case FONTS: name = "fonts"; break;
- case GRADIENTS: name = "gradients"; break;
case ICONS: name = "icons"; break;
case KEYS: name = "keys"; break;
case MARKERS: name = "markers"; break;
case NONE: name = ""; break;
+ case PAINT: name = "paint"; break;
case PALETTES: name = "palettes"; break;
- case PATTERNS: name = "patterns"; break;
case SYMBOLS: name = "symbols"; break;
case TEMPLATES: name = "templates"; break;
case THEMES: name = "themes"; break;
@@ -430,8 +427,8 @@ char *profile_path(const char *filename)
int problem = errno;
g_warning("Unable to create profile directory (%s) (%d)", g_strerror(problem), problem);
} else {
- gchar const *userDirs[] = { "keys", "templates", "icons", "extensions", "ui",
- "symbols", "themes", "palettes", nullptr };
+ gchar const *userDirs[] = { "keys", "templates", "icons", "extensions", "ui",
+ "symbols", "paint", "themes", "palettes", nullptr };
for (gchar const** name = userDirs; *name; ++name) {
gchar *dir = g_build_filename(prefdir, *name, NULL);
g_mkdir_with_parents(dir, mode);
diff --git a/src/io/resource.h b/src/io/resource.h
index e2f15c142..fc1f06681 100644
--- a/src/io/resource.h
+++ b/src/io/resource.h
@@ -29,13 +29,12 @@ namespace Resource {
enum Type {
EXTENSIONS,
FONTS,
- GRADIENTS,
ICONS,
KEYS,
MARKERS,
NONE,
+ PAINT,
PALETTES,
- PATTERNS,
SCREENS,
TEMPLATES,
TUTORIALS,
diff --git a/src/path-prefix.h b/src/path-prefix.h
index 93af933d1..42c6d474c 100644
--- a/src/path-prefix.h
+++ b/src/path-prefix.h
@@ -42,13 +42,12 @@
# define INKSCAPE_EXTENSIONDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/extensions" )
# define INKSCAPE_FILTERDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/filters" )
# define INKSCAPE_FONTSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/fonts" )
-# define INKSCAPE_GRADIENTSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/gradients" )
# define INKSCAPE_KEYSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/keys" )
# define INKSCAPE_ICONSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/icons" )
# define INKSCAPE_PIXMAPSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/pixmaps" )
# define INKSCAPE_MARKERSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/markers" )
+# define INKSCAPE_PAINTDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/paint" )
# define INKSCAPE_PALETTESDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/palettes" )
-# define INKSCAPE_PATTERNSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/patterns" )
# define INKSCAPE_SCREENSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/screens" )
# define INKSCAPE_SYMBOLSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/symbols" )
# define INKSCAPE_THEMEDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/themes" )
@@ -56,9 +55,8 @@
# define INKSCAPE_TEMPLATESDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/templates" )
# define INKSCAPE_UIDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/inkscape/ui" )
//CREATE V0.1 support
-# define CREATE_GRADIENTSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/create/gradients/gimp" )
+# define CREATE_PAINTDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/create/paint" )
# define CREATE_PALETTESDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/create/swatches" )
-# define CREATE_PATTERNSDIR BR_DATADIR( INKSCAPE_LIBPREFIX "/share/create/patterns/vector" )
#elif defined ENABLE_OSX_APP_LOCATIONS // TODO: Is ENABLE_OSX_APP_LOCATIONS still in use?
# define INKSCAPE_DATADIR_REAL "Contents/Resources/share"
# define INKSCAPE_ATTRRELDIR "Contents/Resources/share/inkscape/attributes"
@@ -67,13 +65,12 @@
# define INKSCAPE_EXTENSIONDIR "Contents/Resources/share/inkscape/extensions"
# define INKSCAPE_FILTERDIR "Contents/Resources/share/inkscape/filters"
# define INKSCAPE_FONTSDIR "Contents/Resources/share/inkscape/fonts"
-# define INKSCAPE_GRADIENTSDIR "Contents/Resources/share/inkscape/gradients"
# define INKSCAPE_KEYSDIR "Contents/Resources/share/inkscape/keys"
# define INKSCAPE_ICONSDIR "Contents/Resources/share/inkscape/icons"
# define INKSCAPE_PIXMAPSDIR "Contents/Resources/share/inkscape/pixmaps"
# define INKSCAPE_MARKERSDIR "Contents/Resources/share/inkscape/markers"
+# define INKSCAPE_PAINTDIR "Contents/Resources/share/inkscape/paint"
# define INKSCAPE_PALETTESDIR "Contents/Resources/share/inkscape/palettes"
-# define INKSCAPE_PATTERNSDIR "Contents/Resources/share/inkscape/patterns"
# define INKSCAPE_SCREENSDIR "Contents/Resources/share/inkscape/screens"
# define INKSCAPE_SYMBOLSDIR "Contents/Resources/share/inkscape/symbols"
# define INKSCAPE_THEMEDIR "Contents/Resources/share/inkscape/themes"
@@ -81,9 +78,8 @@
# define INKSCAPE_TEMPLATESDIR "Contents/Resources/share/inkscape/templates"
# define INKSCAPE_UIDIR "Contents/Resources/share/inkscape/ui"
//CREATE V0.1 support
-# define CREATE_GRADIENTSDIR "/Library/Application Support/create/gradients/gimp"
+# define CREATE_PAINTDIR "/Library/Application Support/create/paint"
# define CREATE_PALETTESDIR "/Library/Application Support/create/swatches"
-# define CREATE_PATTERNSDIR "/Library/Application Support/create/patterns/vector"
#else
# define INKSCAPE_DATADIR_REAL append_inkscape_datadir()
# define INKSCAPE_ATTRRELDIR append_inkscape_datadir("inkscape/attributes")
@@ -93,13 +89,12 @@
# define INKSCAPE_EXTENSIONDIR append_inkscape_datadir("inkscape/extensions")
# define INKSCAPE_FILTERDIR append_inkscape_datadir("inkscape/filters")
# define INKSCAPE_FONTSDIR append_inkscape_datadir("inkscape/fonts")
-# define INKSCAPE_GRADIENTSDIR append_inkscape_datadir("inkscape/gradients")
# define INKSCAPE_KEYSDIR append_inkscape_datadir("inkscape/keys")
# define INKSCAPE_ICONSDIR append_inkscape_datadir("inkscape/icons")
# define INKSCAPE_PIXMAPSDIR append_inkscape_datadir("inkscape/pixmaps")
# define INKSCAPE_MARKERSDIR append_inkscape_datadir("inkscape/markers")
+# define INKSCAPE_PAINTDIR append_inkscape_datadir("inkscape/paint")
# define INKSCAPE_PALETTESDIR append_inkscape_datadir("inkscape/palettes")
-# define INKSCAPE_PATTERNSDIR append_inkscape_datadir("inkscape/patterns")
# define INKSCAPE_SCREENSDIR append_inkscape_datadir("inkscape/screens")
# define INKSCAPE_SYMBOLSDIR append_inkscape_datadir("inkscape/symbols")
# define INKSCAPE_THEMEDIR append_inkscape_datadir("inkscape/themes")
@@ -107,9 +102,8 @@
# define INKSCAPE_TEMPLATESDIR append_inkscape_datadir("inkscape/templates")
# define INKSCAPE_UIDIR append_inkscape_datadir("inkscape/ui")
//CREATE V0.1 support
-# define CREATE_GRADIENTSDIR append_inkscape_datadir("create/gradients/gimp")
+# define CREATE_PAINTDIR append_inkscape_datadir("create/paint")
# define CREATE_PALETTESDIR append_inkscape_datadir("create/swatches")
-# define CREATE_PATTERNSDIR append_inkscape_datadir("create/patterns/vector")
#endif
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index d84ac8be4..56b0ef983 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -140,6 +140,7 @@ set(ui_SRC
dialog/svg-preview.cpp
dialog/swatches.cpp
dialog/symbols.cpp
+ dialog/paint-servers.cpp
dialog/template-load-tab.cpp
dialog/template-widget.cpp
dialog/text-edit.cpp
@@ -307,6 +308,7 @@ set(ui_SRC
dialog/svg-preview.h
dialog/swatches.h
dialog/symbols.h
+ dialog/paint-servers.h
dialog/template-load-tab.h
dialog/template-widget.h
dialog/text-edit.h
@@ -426,7 +428,7 @@ set(ui_SRC
widget/notebook-page.h
widget/object-composite-settings.h
widget/page-sizer.h
- widget/pages-skeleton.h
+ widget/pages-skeleton.h
widget/panel.h
widget/point.h
widget/preferences-widget.h
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index 0bcf7727c..474c89b4c 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -31,6 +31,7 @@
#include "ui/dialog/livepatheffect-editor.h"
#include "ui/dialog/memory.h"
#include "ui/dialog/messages.h"
+#include "ui/dialog/paint-servers.h"
#include "ui/dialog/prototype.h"
#include "ui/dialog/symbols.h"
#include "ui/dialog/tile.h"
@@ -129,6 +130,7 @@ DialogManager::DialogManager() {
registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>);
registerFactory("TileDialog", &create<ArrangeDialog, FloatingBehavior>);
registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>);
+ registerFactory("PaintServers", &create<PaintServersDialog, FloatingBehavior>);
registerFactory("StyleDialog", &create<StyleDialog, FloatingBehavior>);
#if HAVE_POTRACE
@@ -149,7 +151,7 @@ DialogManager::DialogManager() {
registerFactory("CloneTiler", &create<CloneTiler, FloatingBehavior>);
registerFactory("XmlTree", &create<XmlTree, FloatingBehavior>);
registerFactory("Selectors", &create<SelectorsDialog, FloatingBehavior>);
-
+
} else {
registerFactory("Prototype", &create<Prototype, DockBehavior>);
@@ -175,6 +177,7 @@ DialogManager::DialogManager() {
registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>);
registerFactory("TileDialog", &create<ArrangeDialog, DockBehavior>);
registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>);
+ registerFactory("PaintServers", &create<PaintServersDialog, DockBehavior>);
#if HAVE_POTRACE
registerFactory("Trace", &create<TraceDialog, DockBehavior>);
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index 1584a7662..9f05cece1 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -1541,11 +1541,11 @@ void InkscapePreferences::initPageIO()
_page_svgexport.add_group_header( _("SVG 2"));
_svgexport_insert_text_fallback.init( _("Insert SVG 1.1 fallback in text."), "/options/svgexport/text_insertfallback", true );
_svgexport_insert_mesh_polyfill.init( _("Insert Mesh Gradient JavaScript polyfill."), "/options/svgexport/mesh_insertpolyfill", true );
- _svgexport_insert_mesh_polyfill.init( _("Insert Hatch Paint Server JavaScript polyfill."), "/options/svgexport/hatch_insertpolyfill", true );
+ _svgexport_insert_hatch_polyfill.init( _("Insert Hatch Paint Server JavaScript polyfill."), "/options/svgexport/hatch_insertpolyfill", true );
_page_svgexport.add_line( false, "", _svgexport_insert_text_fallback, "", _("Adds fallback options for non-SVG 2 renderers."), false);
_page_svgexport.add_line( false, "", _svgexport_insert_mesh_polyfill, "", _("Adds JavaScript polyfill to render meshes."), false);
- _page_svgexport.add_line( false, "", _svgexport_insert_mesh_polyfill, "", _("Adds JavaScript polyfill to render hatches (linear and absolute paths)."), false);
+ _page_svgexport.add_line( false, "", _svgexport_insert_hatch_polyfill, "", _("Adds JavaScript polyfill to render hatches (linear and absolute paths)."), false);
// SVG Export Options (SVG 2 -> SVG 1)
_page_svgexport.add_group_header( _("SVG 2 to SVG 1.1"));
@@ -2601,9 +2601,16 @@ void InkscapePreferences::initPageSystem()
_sys_user_symbols_dir.init((char const *)IO::Resource::get_path(IO::Resource::USER, IO::Resource::SYMBOLS, ""),
_("Open symbols folder"));
+
_page_system.add_line(true, _("User symbols: "), _sys_user_symbols_dir, "", _("Location of the user’s symbols"),
true);
+ _sys_user_paint_servers_dir.init((char const *)IO::Resource::get_path(IO::Resource::USER, IO::Resource::PAINT, ""),
+ _("Open paint servers folder"));
+
+ _page_system.add_line(true, _("User paint servers: "), _sys_user_paint_servers_dir, "",
+ _("Location of the user’s paint servers"), true);
+
_sys_user_palettes_dir.init((char const *)IO::Resource::get_path(IO::Resource::USER, IO::Resource::PALETTES, ""),
_("Open palettes folder"));
_page_system.add_line(true, _("User palettes: "), _sys_user_palettes_dir, "", _("Location of the user’s palettes"),
diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h
index 1c9fe1f7b..06ff7a51e 100644
--- a/src/ui/dialog/inkscape-preferences.h
+++ b/src/ui/dialog/inkscape-preferences.h
@@ -340,7 +340,7 @@ protected:
UI::Widget::PrefCheckButton _markers_color_stock;
UI::Widget::PrefCheckButton _markers_color_custom;
UI::Widget::PrefCheckButton _markers_color_update;
-
+
UI::Widget::PrefCheckButton _cleanup_swatches;
UI::Widget::PrefSpinButton _importexport_export_res;
@@ -380,6 +380,7 @@ protected:
UI::Widget::PrefOpenFolder _sys_user_palettes_dir;
UI::Widget::PrefOpenFolder _sys_user_templates_dir;
UI::Widget::PrefOpenFolder _sys_user_symbols_dir;
+ UI::Widget::PrefOpenFolder _sys_user_paint_servers_dir;
Gtk::Entry _sys_user_cache;
Gtk::Entry _sys_data;
Gtk::TextView _sys_icon;
@@ -485,6 +486,7 @@ protected:
// SVG Output export:
UI::Widget::PrefCheckButton _svgexport_insert_text_fallback;
UI::Widget::PrefCheckButton _svgexport_insert_mesh_polyfill;
+ UI::Widget::PrefCheckButton _svgexport_insert_hatch_polyfill;
UI::Widget::PrefCheckButton _svgexport_remove_marker_auto_start_reverse;
UI::Widget::PrefCheckButton _svgexport_remove_marker_context_paint;
diff --git a/src/ui/dialog/paint-servers.cpp b/src/ui/dialog/paint-servers.cpp
new file mode 100644
index 000000000..1de425a97
--- /dev/null
+++ b/src/ui/dialog/paint-servers.cpp
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief Paint Servers dialog
+ */
+/* Authors:
+ * Valentin Ionita
+ *
+ * Copyright (C) 2019 Valentin Ionita
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <utility>
+
+#include <giomm/listmodel.h>
+#include <glibmm/regex.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/iconview.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/stockid.h>
+#include <gtkmm/switch.h>
+
+#include "document.h"
+#include "inkscape.h"
+#include "paint-servers.h"
+#include "path-prefix.h"
+#include "style.h"
+#include "verbs.h"
+
+#include "io/resource.h"
+#include "object/sp-defs.h"
+#include "object/sp-hatch.h"
+#include "object/sp-pattern.h"
+#include "object/sp-root.h"
+#include "object/sp-shape.h"
+#include "ui/cache/svg_preview_cache.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+static Glib::ustring const wrapper = R"=====(
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+ <defs id="Defs"/>
+ <rect id="Back" x="0" y="0" width="100px" height="100px" fill="lightgray"/>
+ <rect id="Rect" x="0" y="0" width="100px" height="100px" stroke="black"/>
+</svg>
+)=====";
+
+class PaintServersColumns : public Gtk::TreeModel::ColumnRecord {
+ public:
+ Gtk::TreeModelColumn<Glib::ustring> id;
+ Gtk::TreeModelColumn<Glib::ustring> paint;
+ Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> pixbuf;
+ Gtk::TreeModelColumn<Glib::ustring> document;
+
+ PaintServersColumns() {
+ add(id);
+ add(paint);
+ add(pixbuf);
+ add(document);
+ }
+};
+
+PaintServersColumns *PaintServersDialog::getColumns() { return new PaintServersColumns(); }
+
+// Constructor
+PaintServersDialog::PaintServersDialog(gchar const *prefsPath)
+ : Inkscape::UI::Widget::Panel(prefsPath, SP_VERB_DIALOG_PAINT)
+ , current_store(ALLDOCS)
+ , desktop(SP_ACTIVE_DESKTOP)
+ , target_selected(true)
+{
+ store[ALLDOCS] = Gtk::ListStore::create(*getColumns());
+ store[CURRENTDOC] = Gtk::ListStore::create(*getColumns());
+
+ // Grid holding the contents
+ Gtk::Grid *grid = Gtk::manage(new Gtk::Grid());
+ grid->set_margin_start(3);
+ grid->set_margin_end(3);
+ grid->set_margin_top(3);
+ grid->set_row_spacing(3);
+ _getContents()->pack_start(*grid, Gtk::PACK_EXPAND_WIDGET);
+
+ // Grid row 0
+ Gtk::Label *file_label = Gtk::manage(new Gtk::Label(_("Server: ")));
+ grid->attach(*file_label, 0, 0, 1, 1);
+
+ dropdown = Gtk::manage(new Gtk::ComboBoxText());
+ dropdown->append(ALLDOCS);
+ dropdown->append(CURRENTDOC);
+ document_map[CURRENTDOC] = desktop->getDocument();
+ dropdown->set_active_text(ALLDOCS);
+ dropdown->set_hexpand();
+ grid->attach(*dropdown, 1, 0, 1, 1);
+
+ // Grid row 1
+ Gtk::Label *fill_label = Gtk::manage(new Gtk::Label(_("Change: ")));
+ grid->attach(*fill_label, 0, 1, 1, 1);
+
+ target_dropdown = Gtk::manage(new Gtk::ComboBoxText());
+ target_dropdown->append(FILL);
+ target_dropdown->append(STROKE);
+ target_dropdown->set_active_text(FILL);
+ target_dropdown->set_hexpand();
+ grid->attach(*target_dropdown, 1, 1, 1, 1);
+
+ // Grid row 2
+ icon_view = Gtk::manage(new Gtk::IconView(
+ static_cast<Glib::RefPtr<Gtk::TreeModel>>(store[current_store])
+ ));
+ icon_view->set_tooltip_column(0);
+ icon_view->set_pixbuf_column(2);
+ icon_view->set_size_request(200, 300);
+ icon_view->show_all_children();
+ icon_view->set_selection_mode(Gtk::SELECTION_SINGLE);
+ icon_view->set_activate_on_single_click(true);
+
+ Gtk::ScrolledWindow *scroller = Gtk::manage(new Gtk::ScrolledWindow());
+ scroller->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
+ scroller->set_hexpand();
+ scroller->set_vexpand();
+ scroller->add(*icon_view);
+ grid->attach(*scroller, 0, 2, 2, 1);
+
+ // Events
+ target_dropdown->signal_changed().connect(
+ sigc::mem_fun(*this, &PaintServersDialog::on_target_changed)
+ );
+
+ dropdown->signal_changed().connect(
+ sigc::mem_fun(*this, &PaintServersDialog::on_document_changed)
+ );
+
+ icon_view->signal_item_activated().connect(
+ sigc::mem_fun(*this, &PaintServersDialog::on_item_activated)
+ );
+
+ desktop->getDocument()->getDefs()->connectModified(
+ sigc::mem_fun(*this, &PaintServersDialog::load_current_document)
+ );
+
+ // Get wrapper document (rectangle to fill with paint server).
+ preview_document = SPDocument::createNewDocFromMem(wrapper.c_str(), wrapper.length(), true);
+
+ SPObject *rect = preview_document->getObjectById("Rect");
+ SPObject *defs = preview_document->getObjectById("Defs");
+ if (!rect || !defs) {
+ std::cerr << "PaintServersDialog::PaintServersDialog: Failed to get wrapper defs or rectangle!!" << std::endl;
+ }
+
+ // Set up preview document.
+ unsigned key = SPItem::display_key_new(1);
+ preview_document->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ preview_document->ensureUpToDate();
+ renderDrawing.setRoot(preview_document->getRoot()->invoke_show(renderDrawing, key, SP_ITEM_SHOW_DISPLAY));
+
+ // Load paint servers from resource files
+ load_sources();
+}
+
+PaintServersDialog::~PaintServersDialog() = default;
+
+// Get url or color value.
+Glib::ustring get_url(Glib::ustring paint)
+{
+
+ Glib::MatchInfo matchInfo;
+
+ // Paint server
+ static Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create(":(url\\(#([A-z0-9\\-_\\.#])*\\))");
+ regex1->match(paint, matchInfo);
+
+ if (matchInfo.matches()) {
+ return matchInfo.fetch(1);
+ }
+
+ // Color
+ static Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create(":(([A-z0-9#])*)");
+ regex2->match(paint, matchInfo);
+
+ if (matchInfo.matches()) {
+ return matchInfo.fetch(1);
+ }
+
+ return Glib::ustring();
+}
+
+// This is too complicated to use selectors!
+void recurse_find_paint(SPObject* in, std::vector<Glib::ustring>& list)
+{
+
+ // Add paint servers in <defs> section.
+ if (dynamic_cast<SPPaintServer *>(in)) {
+ if (in->getId()) {
+ // Need to check as one can't construct Glib::ustring with nullptr.
+ list.push_back (Glib::ustring("url(#") + in->getId() + ")");
+ }
+ // Don't recurse into paint servers.
+ return;
+ }
+
+ // Add paint servers referenced by shapes.
+ if (dynamic_cast<SPShape *>(in)) {
+ list.push_back (get_url(in->style->fill.write()));
+ list.push_back (get_url(in->style->stroke.write()));
+ }
+
+ for (auto child: in->childList(false)) {
+ recurse_find_paint(child, list);
+ }
+}
+
+// Load paint servers from all the files associated
+void PaintServersDialog::load_sources()
+{
+
+ // Extract paints from the current file
+ load_document(desktop->getDocument());
+
+ // Extract out paints from files in share/paint.
+ for (auto &path : get_filenames(Inkscape::IO::Resource::PAINT, { ".svg" })) {
+ SPDocument *document = SPDocument::createNewDoc(path.c_str(), FALSE);
+ Glib::ustring document_title = Glib::ustring(document->getRoot()->title());
+
+ load_document(document);
+ }
+}
+
+Glib::RefPtr<Gdk::Pixbuf> PaintServersDialog::get_pixbuf(SPDocument *document, Glib::ustring paint, Glib::ustring *id)
+{
+
+ SPObject *rect = preview_document->getObjectById("Rect");
+ SPObject *defs = preview_document->getObjectById("Defs");
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf(nullptr);
+ if (paint.empty()) {
+ return pixbuf;
+ }
+
+ // Set style on wrapper
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css, "fill", paint.c_str());
+ rect->changeCSS(css, "style");
+ sp_repr_css_attr_unref(css);
+
+ // Insert paint into defs if required
+ Glib::MatchInfo matchInfo;
+ static Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("url\\(#([A-Za-z0-9#._-]*)\\)");
+ regex->match(paint, matchInfo);
+ if (matchInfo.matches()) {
+ *id = matchInfo.fetch(1);
+
+ // Delete old paint if necessary
+ std::vector<SPObject *> old_paints = preview_document->getObjectsBySelector("defs > *");
+ for (auto paint : old_paints) {
+ paint->deleteObject(false);
+ }
+
+ // Add new paint
+ SPObject *new_paint = document->getObjectById(*id);
+ if (!new_paint) {
+ std::cerr << "PaintServersDialog::load_document: cannot find paint server: " << id << std::endl;
+ return pixbuf;
+ }
+
+ // Create a copy repr of the paint
+ Inkscape::XML::Document *xml_doc = preview_document->getReprDoc();
+ Inkscape::XML::Node *repr = new_paint->getRepr()->duplicate(xml_doc);
+ defs->appendChild(repr);
+ } else {
+ // Temporary block solid color fills.
+ return pixbuf;
+ }
+
+ preview_document->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ preview_document->ensureUpToDate();
+
+ Geom::OptRect dbox = dynamic_cast<SPItem *>(rect)->visualBounds();
+
+ if (!dbox) {
+ return pixbuf;
+ }
+
+ double size = std::max(dbox->width(), dbox->height());
+
+ pixbuf = Glib::wrap(render_pixbuf(renderDrawing, 1, *dbox, size));
+
+ return pixbuf;
+}
+
+// Load paint server from the given document
+void PaintServersDialog::load_document(SPDocument *document)
+{
+ PaintServersColumns *columns = getColumns();
+ Glib::ustring document_title;
+ if (!document->getRoot()->title()) {
+ document_title = CURRENTDOC;
+ } else {
+ document_title = Glib::ustring(document->getRoot()->title());
+ }
+ bool has_server_elements = false;
+
+ // Find all paints
+ std::vector<Glib::ustring> paints;
+ recurse_find_paint(document->getRoot(), paints);
+
+ // Sort and remove duplicates.
+ std::sort(paints.begin(), paints.end());
+ paints.erase(std::unique(paints.begin(), paints.end()), paints.end());
+
+ if (paints.size() && store.find(document_title) == store.end()) {
+ store[document_title] = Gtk::ListStore::create(*getColumns());
+ }
+
+ // iterating though servers
+ for (auto paint : paints) {
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf(nullptr);
+ Glib::ustring id;
+ pixbuf = get_pixbuf(document, paint, &id);
+ if (!pixbuf) {
+ continue;
+ }
+
+ // Save as a ListStore column
+ Gtk::ListStore::iterator iter = store[ALLDOCS]->append();
+ (*iter)[columns->id] = id;
+ (*iter)[columns->paint] = paint;
+ (*iter)[columns->pixbuf] = pixbuf;
+ (*iter)[columns->document] = document_title;
+
+ iter = store[document_title]->append();
+ (*iter)[columns->id] = id;
+ (*iter)[columns->paint] = paint;
+ (*iter)[columns->pixbuf] = pixbuf;
+ (*iter)[columns->document] = document_title;
+ has_server_elements = true;
+ }
+
+ if (has_server_elements && document_map.find(document_title) == document_map.end()) {
+ document_map[document_title] = document;
+ dropdown->append(document_title);
+ }
+}
+
+void PaintServersDialog::load_current_document(SPObject * /*object*/, guint /*flags*/)
+{
+ PaintServersColumns *columns = getColumns();
+ SPDocument *document = desktop->getDocument();
+ Glib::RefPtr<Gtk::ListStore> current = store[CURRENTDOC];
+
+ std::vector<Glib::ustring> paints;
+ std::vector<Glib::ustring> paints_current;
+ std::vector<Glib::ustring> paints_missing;
+ recurse_find_paint(document->getDefs(), paints);
+
+ std::sort(paints.begin(), paints.end());
+ paints.erase(std::unique(paints.begin(), paints.end()), paints.end());
+
+ // Delete the server from the store if it doesn't exist in the current document
+ for (auto iter = current->children().begin(); iter != current->children().end();) {
+ Gtk::TreeRow server = *iter;
+
+ if (std::find(paints.begin(), paints.end(), server[columns->paint]) == paints.end()) {
+ iter = current->erase(server);
+ } else {
+ paints_current.push_back(server[columns->paint]);
+ iter++;
+ }
+ }
+
+ for (auto s : paints) {
+ if (std::find(paints_current.begin(), paints_current.end(), s) == paints_current.end()) {
+ std::cout << "missing " << s << std::endl;
+ paints_missing.push_back(s);
+ }
+ }
+ std::cout << std::endl;
+
+ if (!paints_missing.size()) {
+ return;
+ }
+
+ for (auto paint : paints_missing) {
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf(nullptr);
+ Glib::ustring id;
+ pixbuf = get_pixbuf(document, paint, &id);
+ if (!pixbuf) {
+ continue;
+ }
+
+ Gtk::ListStore::iterator iter = current->append();
+ (*iter)[columns->id] = id;
+ (*iter)[columns->paint] = paint;
+ (*iter)[columns->pixbuf] = pixbuf;
+ (*iter)[columns->document] = CURRENTDOC;
+ }
+}
+
+void PaintServersDialog::on_target_changed()
+{
+ target_selected = !target_selected;
+}
+
+void PaintServersDialog::on_document_changed()
+{
+ current_store = dropdown->get_active_text();
+ icon_view->set_model(store[current_store]);
+}
+
+void PaintServersDialog::on_item_activated(const Gtk::TreeModel::Path& path)
+{
+ // Get the current selected elements
+ Selection *selection = desktop->getSelection();
+ std::vector<SPObject*> const selected_items(selection->items().begin(), selection->items().end());
+
+ if (!selected_items.size()) {
+ return;
+ }
+
+ PaintServersColumns *columns = getColumns();
+ Gtk::ListStore::iterator iter = store[current_store]->get_iter(path);
+ Glib::ustring id = (*iter)[columns->id];
+ Glib::ustring paint = (*iter)[columns->paint];
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = (*iter)[columns->pixbuf];
+ Glib::ustring document_title = (*iter)[columns->document];
+ Glib::ustring attribute = target_selected ? "fill:" : "stroke:";
+ Glib::ustring new_value(attribute + paint);
+ SPDocument *document = document_map[document_title];
+ SPObject *paint_server = document->getObjectById(id);
+ SPDocument *document_target = desktop->getDocument();
+
+ bool paint_server_exists = false;
+ for (auto server : store[CURRENTDOC]->children()) {
+ if (server[columns->id] == id) {
+ paint_server_exists = true;
+ break;
+ }
+ }
+
+ if (!paint_server_exists) {
+ // Add the paint server to the current document definition
+ Inkscape::XML::Document *xml_doc = document_target->getReprDoc();
+ Inkscape::XML::Node *repr = paint_server->getRepr()->duplicate(xml_doc);
+ document_target->getDefs()->appendChild(repr);
+ Inkscape::GC::release(repr);
+
+ // Add the pixbuf to the current document store
+ iter = store[CURRENTDOC]->append();
+ (*iter)[columns->id] = id;
+ (*iter)[columns->paint] = paint;
+ (*iter)[columns->pixbuf] = pixbuf;
+ (*iter)[columns->document] = document_title;
+ }
+
+ // Recursively find elements in groups, if any
+ std::vector<SPObject*> items;
+ for (auto item : selected_items) {
+ std::vector<SPObject*> current_items = extract_elements(item);
+ items.insert(std::end(items), std::begin(current_items), std::end(current_items));
+ }
+
+ static Glib::RefPtr<Glib::Regex> regex_url = Glib::Regex::create("url\\(#([A-z0-9\\-_\\.#])*\\)");
+
+ for (auto item : items) {
+ // FIXME - maybe the item doesn't have that attribute
+ Glib::ustring style = item->getAttribute("style", nullptr);
+ int search_start = style.find(attribute, 0);
+ int search_end = style.find(";", search_start) - search_start;
+ Glib::ustring previous_value = style.substr(search_start + 5, search_end - 5);
+
+ // Set attribute for each selected item
+ style.replace(search_start, search_end, new_value);
+ item->setAttribute("style", style, nullptr);
+
+ // Remove previous paint server, if it exists
+ if (regex_url->match(previous_value)) {
+ previous_value = previous_value.substr(4, previous_value.size() - 5);
+ std::vector<SPObject *> defs = desktop->getDocument()->getDefs()->childList(true);
+ auto it = find_if(defs.begin(), defs.end(),
+ [&previous_value](const SPObject *obj) {return previous_value.compare(obj->getId());}
+ );
+
+ // Check if it actually exists
+ if (it != defs.end()) {
+ // linear and radial gradients reference another target gradient
+ // remove the target gradient only if it's not referenced by
+ // other elements
+ if (dynamic_cast<SPGradient *>(*it)) {
+ if ((*it)->hrefList.size() && !(*it)->hrefList.front()->isReferenced()) {
+ (*it)->hrefList.front()->deleteObject(true, true);
+ }
+ }
+
+ // if no other elements reference this paint server, remove it
+ if (!(*it)->isReferenced()) {
+ (*it)->deleteObject(true, true);
+ }
+ }
+ }
+ }
+}
+
+std::vector<SPObject*> PaintServersDialog::extract_elements(SPObject* item)
+{
+ std::vector<SPObject*> elements;
+ std::vector<SPObject*> children = item->childList(false);
+ if (!children.size()) {
+ elements.push_back(item);
+ } else {
+ for (auto e : children) {
+ std::vector<SPObject*> current_items = extract_elements(e);
+ elements.insert(std::end(elements), std::begin(current_items), std::end(current_items));
+ }
+ }
+
+ return elements;
+}
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-basic-offset:2
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/dialog/paint-servers.h b/src/ui/dialog/paint-servers.h
new file mode 100644
index 000000000..cfb42f387
--- /dev/null
+++ b/src/ui/dialog/paint-servers.h
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * @brief Paint Servers dialog
+ */
+/* Authors:
+ * Valentin Ionita
+ *
+ * Copyright (C) 2019 Valentin Ionita
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_DIALOG_PAINT_SERVERS_H
+#define INKSCAPE_UI_DIALOG_PAINT_SERVERS_H
+
+#include <glibmm/i18n.h>
+#include <gtkmm.h>
+
+#include "display/drawing.h"
+#include "ui/widget/panel.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class PaintServersColumns; // For Gtk::ListStore
+
+/**
+ * This dialog serves as a preview for different types of paint servers,
+ * currently only predefined. It can set the fill or stroke of the selected
+ * object to the to the paint server you select.
+ *
+ * Patterns and hatches are loaded from the preferences paths and displayed
+ * for each document, for all documents and for the current document.
+ */
+
+class PaintServersDialog : public Inkscape::UI::Widget::Panel {
+
+public:
+ PaintServersDialog(gchar const *prefsPath = "/dialogs/paint");
+ ~PaintServersDialog() override;
+
+ static PaintServersDialog &getInstance() { return *new PaintServersDialog(); };
+ PaintServersDialog(PaintServersDialog const &) = delete;
+ PaintServersDialog &operator=(PaintServersDialog const &) = delete;
+
+ private:
+ static PaintServersColumns *getColumns();
+ void load_sources();
+ void load_document(SPDocument *document);
+ void load_current_document(SPObject *, guint);
+ Glib::RefPtr<Gdk::Pixbuf> get_pixbuf(SPDocument *, Glib::ustring, Glib::ustring *);
+ void on_target_changed();
+ void on_document_changed();
+ void on_item_activated(const Gtk::TreeModel::Path &path);
+ std::vector<SPObject *> extract_elements(SPObject *item);
+
+ const Glib::ustring ALLDOCS = _("All paint servers");
+ const Glib::ustring CURRENTDOC = _("Current document");
+ const Glib::ustring FILL = _("Fill");
+ const Glib::ustring STROKE = _("Stroke");
+ std::map<Glib::ustring, Glib::RefPtr<Gtk::ListStore>> store;
+ Glib::ustring current_store;
+ std::map<Glib::ustring, SPDocument *> document_map;
+ SPDocument *preview_document;
+ Inkscape::Drawing renderDrawing;
+ Gtk::ComboBoxText *dropdown;
+ Gtk::IconView *icon_view;
+ SPDesktop *desktop;
+ Gtk::ComboBoxText *target_dropdown;
+ bool target_selected;
+};
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+#endif // SEEN INKSCAPE_UI_DIALOG_PAINT_SERVERS_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-basic-offset:2
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=2:tabstop=8:softtabstop=2:fileencoding=utf-8:textwidth=99 :
diff --git a/src/verbs.cpp b/src/verbs.cpp
index 66b85d9a9..f36ef4c90 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -78,6 +78,7 @@
#include "ui/dialog/layers.h"
#include "ui/dialog/new-from-template.h"
#include "ui/dialog/object-properties.h"
+#include "ui/dialog/paint-servers.h"
#include "ui/dialog/save-template-dialog.h"
#include "ui/dialog/swatches.h"
#include "ui/dialog/symbols.h"
@@ -2169,6 +2170,9 @@ void DialogVerb::perform(SPAction *action, void *data)
case SP_VERB_DIALOG_SYMBOLS:
dt->_dlg_mgr->showDialog("Symbols");
break;
+ case SP_VERB_DIALOG_PAINT:
+ dt->_dlg_mgr->showDialog("PaintServers");
+ break;
case SP_VERB_DIALOG_TRANSFORM:
dt->_dlg_mgr->showDialog("Transformation");
break;
@@ -3096,6 +3100,9 @@ Verb *Verb::_base_verbs[] = {
N_("Select colors from a swatches palette"), INKSCAPE_ICON("swatches")),
new DialogVerb(SP_VERB_DIALOG_SYMBOLS, "DialogSymbols", N_("S_ymbols..."),
N_("Select symbol from a symbols palette"), INKSCAPE_ICON("symbols")),
+ new DialogVerb(SP_VERB_DIALOG_PAINT, "DialogPaintServers", N_("_Paint Servers..."),
+ // FIXME missing Inkscape Paint Server Icon
+ N_("Select paint server from a collection"), INKSCAPE_ICON("symbols")),
new DialogVerb(SP_VERB_DIALOG_TRANSFORM, "DialogTransform", N_("Transfor_m..."),
N_("Precisely control objects' transformations"), INKSCAPE_ICON("dialog-transform")),
new DialogVerb(SP_VERB_DIALOG_ALIGN_DISTRIBUTE, "DialogAlignDistribute", N_("_Align and Distribute..."),
diff --git a/src/verbs.h b/src/verbs.h
index 91bcbf9d7..bef596379 100644
--- a/src/verbs.h
+++ b/src/verbs.h
@@ -320,6 +320,7 @@ enum {
SP_VERB_DIALOG_GLYPHS,
SP_VERB_DIALOG_SWATCHES,
SP_VERB_DIALOG_SYMBOLS,
+ SP_VERB_DIALOG_PAINT,
SP_VERB_DIALOG_TRANSFORM,
SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
SP_VERB_DIALOG_SPRAY_OPTION,
diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp
index b640ee22f..e1a6c2b5b 100644
--- a/src/widgets/paint-selector.cpp
+++ b/src/widgets/paint-selector.cpp
@@ -35,6 +35,7 @@
#include "io/sys.h"
+#include "object/sp-hatch.h"
#include "object/sp-linear-gradient.h"
#include "object/sp-mesh-gradient.h"
#include "object/sp-pattern.h"
@@ -83,6 +84,7 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe
static void sp_paint_selector_set_mode_mesh(SPPaintSelector *psel, SPPaintSelector::Mode mode);
#endif
static void sp_paint_selector_set_mode_pattern(SPPaintSelector *psel, SPPaintSelector::Mode mode);
+static void sp_paint_selector_set_mode_hatch(SPPaintSelector *psel, SPPaintSelector::Mode mode);
static void sp_paint_selector_set_mode_swatch(SPPaintSelector *psel, SPPaintSelector::Mode mode);
static void sp_paint_selector_set_mode_unset(SPPaintSelector *psel);
@@ -404,6 +406,9 @@ void SPPaintSelector::setMode(Mode mode)
case MODE_PATTERN:
sp_paint_selector_set_mode_pattern(this, mode);
break;
+ case MODE_HATCH:
+ sp_paint_selector_set_mode_hatch(this, mode);
+ break;
case MODE_SWATCH:
sp_paint_selector_set_mode_swatch(this, mode);
break;
@@ -658,7 +663,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec
{
using Inkscape::UI::Widget::ColorNotebook;
- if ((psel->mode == SPPaintSelector::MODE_SWATCH)
+ if ((psel->mode == SPPaintSelector::MODE_SWATCH)
|| (psel->mode == SPPaintSelector::MODE_GRADIENT_LINEAR)
|| (psel->mode == SPPaintSelector::MODE_GRADIENT_RADIAL) ) {
SPGradientSelector *gsel = getGradientFromData(psel);
@@ -1197,7 +1202,7 @@ ink_pattern_menu_populate_menu(GtkWidget *combo, SPDocument *doc)
// find and load patterns.svg
if (patterns_doc == nullptr) {
- char *patterns_source = g_build_filename(INKSCAPE_PATTERNSDIR, "patterns.svg", NULL);
+ char *patterns_source = g_build_filename(INKSCAPE_PAINTDIR, "patterns.svg", NULL);
if (Inkscape::IO::file_test(patterns_source, G_FILE_TEST_IS_REGULAR)) {
patterns_doc = SPDocument::createNewDoc(patterns_source, FALSE);
}
@@ -1378,6 +1383,26 @@ static void sp_paint_selector_set_mode_pattern(SPPaintSelector *psel, SPPaintSel
#endif
}
+static void sp_paint_selector_set_mode_hatch(SPPaintSelector *psel, SPPaintSelector::Mode mode)
+{
+ if (mode == SPPaintSelector::MODE_HATCH) {
+ sp_paint_selector_set_style_buttons(psel, psel->unset);
+ }
+
+ gtk_widget_set_sensitive(psel->style, TRUE);
+
+ if (psel->mode == SPPaintSelector::MODE_HATCH) {
+ /* Already have hatch menu, for the moment unset */
+ } else {
+ sp_paint_selector_clear_frame(psel);
+
+ gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Hatch fill</b>"));
+ }
+#ifdef SP_PS_VERBOSE
+ g_print("Hatch req\n");
+#endif
+}
+
gboolean SPPaintSelector::isSeparator (GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) {
gboolean sep = FALSE;
@@ -1534,6 +1559,8 @@ SPPaintSelector::Mode SPPaintSelector::getModeForStyle(SPStyle const & style, Fi
#endif
} else if (SP_IS_PATTERN(server)) {
mode = MODE_PATTERN;
+ } else if (SP_IS_HATCH(server)) {
+ mode = MODE_HATCH;
} else {
g_warning( "file %s: line %d: Unknown paintserver", __FILE__, __LINE__ );
mode = MODE_NONE;
diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h
index 4a6db3121..7d142f327 100644
--- a/src/widgets/paint-selector.h
+++ b/src/widgets/paint-selector.h
@@ -54,6 +54,7 @@ struct SPPaintSelector {
MODE_GRADIENT_MESH,
#endif
MODE_PATTERN,
+ MODE_HATCH,
MODE_SWATCH,
MODE_UNSET
} ;