From: tweenk Date: Sat, 21 Feb 2009 01:59:56 +0000 (+0000) Subject: Move files from the src/dialogs/ directory to the places where they X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=a73e5f92baa51f76f70126ed64cabac4fa811764;p=inkscape.git Move files from the src/dialogs/ directory to the places where they should be. Build libinkscape.a - should reduce link time. --- diff --git a/src/Makefile.am b/src/Makefile.am index dece3edcf..517e89f1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,10 +1,7 @@ ## Process this file with automake to produce Makefile.in - # ################################################ -# # G L O B A L -# # ################################################ # Should work in either automake1.7 or 1.8, but 1.6 doesn't @@ -16,6 +13,40 @@ AUTOMAKE_OPTIONS = 1.7 subdir-objects # Executables compiled by "make" and installed by "make install" bin_PROGRAMS = inkscape inkview +# Libraries which should be compiled by "make" but not installed. +# Use this only for libraries that are really standalone, rather than for +# source tree subdirectories. +if WITH_INKBOARD +libpedro = pedro/libpedro.a +endif +noinst_LIBRARIES = \ + libinkscape.a \ + dom/libdom.a \ + libcroco/libcroco.a \ + libavoid/libavoid.a \ + libgdl/libgdl.a \ + libcola/libcola.a \ + libvpsc/libvpsc.a \ + livarot/libvarot.a \ + 2geom/lib2geom.a \ + $(libpedro) \ + libinkversion.a + +all_libs = \ + $(noinst_LIBRARIES) \ + $(INKSCAPE_LIBS) \ + $(GNOME_VFS_LIBS) \ + $(XFT_LIBS) \ + $(FREETYPE_LIBS) \ + $(kdeldadd) \ + $(win32ldflags) \ + $(CARBON_LDFLAGS) \ + $(PERL_LIBS) \ + $(PYTHON_LIBS) \ + $(INKBOARD_LIBS) \ + $(LIBWPG_LIBS) \ + $(IMAGEMAGICK_LIBS) + # Add sources common for Inkscape and Inkview to this variable. ink_common_sources = # Add Inkscape-only sources here. @@ -23,11 +54,6 @@ inkscape_SOURCES = # Add Inkview-only sources here. inkview_SOURCES = -# Libraries which should be compiled by "make" but not installed. -# Use this only for libraries that are really standalone, rather than for -# source tree subdirectories. -noinst_LIBRARIES = $(inkscape_private_libs) - INCLUDES = \ $(PERL_CFLAGS) $(PYTHON_CFLAGS) \ $(FREETYPE_CFLAGS) \ @@ -70,43 +96,6 @@ inkjar_dir = inkjar inkjar_libs = inkjar/libinkjar.a endif -# Extra files to remove when doing "make distclean" -DISTCLEANFILES = \ - helper/sp-marshal.cpp \ - helper/sp-marshal.h \ - inkscape-version.cpp - -if WITH_INKBOARD -libpedro = pedro/libpedro.a -endif - -inkscape_private_libs = \ - dom/libdom.a \ - libcroco/libcroco.a \ - libavoid/libavoid.a \ - libgdl/libgdl.a \ - libcola/libcola.a \ - libvpsc/libvpsc.a \ - livarot/libvarot.a \ - 2geom/lib2geom.a \ - $(libpedro) \ - libinkversion.a - -all_libs = \ - $(inkscape_private_libs) \ - $(INKSCAPE_LIBS) \ - $(GNOME_VFS_LIBS) \ - $(XFT_LIBS) \ - $(FREETYPE_LIBS) \ - $(kdeldadd) \ - $(win32ldflags) \ - $(CARBON_LDFLAGS) \ - $(PERL_LIBS) \ - $(PYTHON_LIBS) \ - $(INKBOARD_LIBS) \ - $(LIBWPG_LIBS) \ - $(IMAGEMAGICK_LIBS) - # Include all partial makefiles from subdirectories include Makefile_insert include application/Makefile_insert @@ -208,19 +197,57 @@ EXTRA_DIST = \ traits/reference.h \ $(jabber_whiteboard_SOURCES) +# Extra files to remove when doing "make distclean" +DISTCLEANFILES = \ + helper/sp-marshal.cpp \ + helper/sp-marshal.h \ + inkscape-version.cpp + # ################################################ -# # B I N A R I E S -# # ################################################ -inkscape_SOURCES += main.cpp $(ink_common_sources) $(win32_sources) +# this should speed up the build +libinkscape_a_SOURCES = $(ink_common_sources) + +inkscape_SOURCES += main.cpp $(win32_sources) inkscape_LDADD = $(all_libs) inkscape_LDFLAGS = --export-dynamic $(kdeldflags) -inkview_SOURCES += inkview.cpp $(ink_common_sources) $(win32_sources) +inkview_SOURCES += inkview.cpp $(win32_sources) inkview_LDADD = $(all_libs) +# ################################################ +# VERSION REPORTING +# ################################################ + +libinkversion_a_SOURCES = inkscape-version.cpp inkscape-version.h + +if USE_SVN_VERSION +inkscape_version_deps = $(top_srcdir)/.svn/entries +endif + +# If this is an SVN snapshot build, regenerate this file every time +# someone updates the SVN working directory. +inkscape-version.cpp: $(inkscape_version_deps) + VER_PREFIX="$(VERSION)"; \ + if test -x "$(srcdir)/.svn" -a ! -z `which svn`; then \ + VER_SVNREV=" r`svn info $(srcdir) | sed -n -e '/^Revision:/s/Revision: \(.*\)/\1/p'`"; \ + if test ! -z "`svn status -q $(srcdir)`"; then \ + VER_CUSTOM=" custom"; \ + fi; \ + fi; \ + VERSION="$$VER_PREFIX$$VER_SVNREV$$VER_CUSTOM"; \ + echo "namespace Inkscape { " \ + "char const *version_string = \"$$VERSION\"; " \ + "}" > inkscape-version.new.cpp; \ + if cmp -s inkscape-version.new.cpp inkscape-version.cpp; then \ + rm inkscape-version.new.cpp; \ + else \ + mv inkscape-version.new.cpp inkscape-version.cpp; \ + fi; \ + echo $$VERSION + # ################################# # ## TESTING STUFF (make check) ### # ################################# diff --git a/src/Makefile_insert b/src/Makefile_insert index 360f69cc4..a3babf265 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -1,22 +1,5 @@ ## Makefile.am fragment, included by src/Makefile.am. - -# ################################################ -# -# I N K S C A P E -# -# ################################################ - -# libinkpre.a: any object that's sharable between inkscape & inkview, -# and isn't needed by object files in subdirectories (i.e. libinkpre.a -# comes before subdirectory libraries on the link line). -# -# Excludes winmain.cpp (a gui wrapper around main): I'm guessing that -# it needs to be explicitly listed as a source of each graphical -# binary: it isn't (to my knowledge) called by main (whether directly -# or indirectly), so I don't think that putting it in a library will -# suffice to get it linked in. Windows devel please confirm. -- pjrm. - ink_common_sources += \ algorithms/find-last-if.h \ algorithms/longest-common-suffix.h \ @@ -137,6 +120,7 @@ ink_common_sources += \ print.cpp print.h \ profile-manager.cpp profile-manager.h \ proj_pt.cpp proj_pt.h \ + rdf.cpp rdf.h \ rect-context.cpp rect-context.h \ require-config.h \ round.h \ @@ -254,8 +238,7 @@ ink_common_sources += \ tools-switch.cpp tools-switch.h \ transf_mat_3x4.cpp transf_mat_3x4.h \ tweak-context.h tweak-context.cpp \ - ui/context-menu.cpp \ - ui/context-menu.h \ + unclump.cpp unclump.h \ undo-stack-observer.h \ unicoderange.cpp unicoderange.h \ unit-constants.h \ @@ -276,33 +259,6 @@ selection.$(OBJEXT): helper/sp-marshal.h sp-object.$(OBJEXT): helper/sp-marshal.h view.$(OBJEXT): helper/sp-marshal.h -libinkversion_a_SOURCES = inkscape-version.cpp inkscape-version.h - -if USE_SVN_VERSION -inkscape_version_deps = $(top_srcdir)/.svn/entries -endif - -# If this is an SVN snapshot build, regenerate this file every time -# someone updates the SVN working directory. -inkscape-version.cpp: $(inkscape_version_deps) - VER_PREFIX="$(VERSION)"; \ - if test -x "$(srcdir)/.svn" -a ! -z `which svn`; then \ - VER_SVNREV=" r`svn info $(srcdir) | sed -n -e '/^Revision:/s/Revision: \(.*\)/\1/p'`"; \ - if test ! -z "`svn status -q $(srcdir)`"; then \ - VER_CUSTOM=" custom"; \ - fi; \ - fi; \ - VERSION="$$VER_PREFIX$$VER_SVNREV$$VER_CUSTOM"; \ - echo "namespace Inkscape { " \ - "char const *version_string = \"$$VERSION\"; " \ - "}" > inkscape-version.new.cpp; \ - if cmp -s inkscape-version.new.cpp inkscape-version.cpp; then \ - rm inkscape-version.new.cpp; \ - else \ - mv inkscape-version.new.cpp inkscape-version.cpp; \ - fi; \ - echo $$VERSION - # ###################### # ### CxxTest stuff #### # ###################### diff --git a/src/conditions.cpp b/src/conditions.cpp index 9a46f27d1..4a18a6913 100644 --- a/src/conditions.cpp +++ b/src/conditions.cpp @@ -19,7 +19,7 @@ #include #include "conditions.h" #include "xml/repr.h" -#include "dialogs/rdf.h" +#include "rdf.h" typedef bool (* condition_evaluator)(SPItem const *item, gchar const *value); diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index 46fb00cca..73cd64665 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -1,9 +1,7 @@ -#define __SP_DESKTOP_EVENTS_C__ - -/* - * Event handlers for SPDesktop - * - * Author: +/** @file + * @brief Event handlers for SPDesktop + */ +/* Author: * Lauris Kaplinski * * Copyright (C) 1999-2002 Lauris Kaplinski @@ -16,30 +14,31 @@ #endif #include #include +#include <2geom/line.h> +#include + +#include "desktop.h" +#include "desktop-handles.h" +#include "dialogs/dialog-events.h" +#include "display/canvas-axonomgrid.h" +#include "display/canvas-grid.h" #include "display/guideline.h" #include "display/snap-indicator.h" +#include "document.h" +#include "event-context.h" +#include "helper/action.h" #include "helper/unit-menu.h" #include "helper/units.h" -#include "desktop.h" -#include "document.h" +#include "message-context.h" +#include "preferences.h" +#include "snap.h" #include "sp-guide.h" +#include "sp-metrics.h" #include "sp-namedview.h" -#include "desktop-handles.h" -#include "event-context.h" +#include "tools-switch.h" +#include "ui/dialog/guides.h" #include "widgets/desktop-widget.h" -#include "sp-metrics.h" -#include -#include "dialogs/dialog-events.h" -#include "message-context.h" #include "xml/repr.h" -#include "dialogs/guidelinedialog.h" -#include "snap.h" -#include "display/canvas-grid.h" -#include "display/canvas-axonomgrid.h" -#include "preferences.h" -#include "helper/action.h" -#include "tools-switch.h" -#include <2geom/line.h> static void snoop_extended(GdkEvent* event, SPDesktop *desktop); static void init_extended(); diff --git a/src/dialogs/Makefile_insert b/src/dialogs/Makefile_insert index f7404a8b2..32a11e831 100644 --- a/src/dialogs/Makefile_insert +++ b/src/dialogs/Makefile_insert @@ -5,47 +5,19 @@ ink_common_sources += \ dialogs/clonetiler.h \ dialogs/dialog-events.cpp \ dialogs/dialog-events.h \ - dialogs/eek-color-def.cpp \ - dialogs/eek-color-def.h \ - dialogs/eek-preview.cpp \ - dialogs/eek-preview.h \ dialogs/export.cpp \ dialogs/export.h \ - dialogs/extensions.cpp \ - dialogs/extensions.h \ - dialogs/fill-style.cpp \ - dialogs/fill-style.h \ dialogs/find.cpp \ dialogs/find.h \ - dialogs/guidelinedialog.cpp \ - dialogs/guidelinedialog.h \ - dialogs/iconpreview.cpp \ - dialogs/iconpreview.h \ - dialogs/in-dt-coordsys.cpp \ - dialogs/in-dt-coordsys.h \ dialogs/input.cpp \ dialogs/input.h \ dialogs/item-properties.cpp \ dialogs/item-properties.h \ - dialogs/layer-properties.cpp \ - dialogs/layer-properties.h \ - dialogs/layers-panel.cpp \ - dialogs/layers-panel.h \ dialogs/object-attributes.cpp \ dialogs/object-attributes.h \ - dialogs/rdf.cpp \ - dialogs/rdf.h \ - dialogs/sp-attribute-widget.cpp \ - dialogs/sp-attribute-widget.h \ dialogs/spellcheck.cpp \ dialogs/spellcheck.h \ - dialogs/stroke-style.cpp \ - dialogs/stroke-style.h \ - dialogs/swatches.cpp \ - dialogs/swatches.h \ dialogs/text-edit.cpp \ dialogs/text-edit.h \ - dialogs/unclump.cpp \ - dialogs/unclump.h \ dialogs/xml-tree.cpp \ dialogs/xml-tree.h diff --git a/src/dialogs/eek-color-def.cpp b/src/dialogs/eek-color-def.cpp deleted file mode 100644 index 85b00b251..000000000 --- a/src/dialogs/eek-color-def.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/** @file - * @brief EEK color definition - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Eek Color Definition. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "config.h" - -#ifdef HAVE_LIBINTL_H -#include -#endif - -#if !defined(_) -#define _(s) gettext(s) -#endif // !defined(_) - -#include "eek-color-def.h" - -namespace eek -{ - -ColorDef::ColorDef() : - descr(_("none")), - r(0), - g(0), - b(0), - none(true), - editable(false) -{ -} - -ColorDef::ColorDef( unsigned int r, unsigned int g, unsigned int b, const std::string& description ) : - descr(description), - r(r), - g(g), - b(b), - none(false), - editable(false) -{ -} - -ColorDef::~ColorDef() -{ -} - -ColorDef::ColorDef( ColorDef const &other ) -{ - if ( this != &other ) { - *this = other; - } -} - -ColorDef& ColorDef::operator=( ColorDef const &other ) -{ - if ( this != & other ) - { - r = other.r; - g = other.g; - b = other.b; - descr = other.descr; - none = other.none; - editable = other.editable; - } - return *this; -} - -class ColorDef::HookData { -public: - HookData( ColorCallback cb, void* data ) {_cb = cb; _data = data;} - ColorCallback _cb; - void* _data; -}; - -void ColorDef::setRGB( unsigned int r, unsigned int g, unsigned int b ) -{ - if ( r != this->r || g != this->g || b != this->b ) { - this->r = r; - this->g = g; - this->b = b; - - // beware of callbacks changing things - for ( std::vector::iterator it = _listeners.begin(); it != _listeners.end(); ++it ) - { - if ( (*it)->_cb ) - { - (*it)->_cb( (*it)->_data ); - } - } - } -} - -void ColorDef::addCallback( ColorCallback cb, void* data ) -{ - _listeners.push_back( new HookData(cb, data) ); -} - -void ColorDef::removeCallback( ColorCallback cb, void* data ) -{ - (void)cb; - (void)data; -} - -} // namespace eek - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/eek-color-def.h b/src/dialogs/eek-color-def.h deleted file mode 100644 index 63cd096be..000000000 --- a/src/dialogs/eek-color-def.h +++ /dev/null @@ -1,102 +0,0 @@ -/** @file - * @brief EEK color definition - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Eek Color Definition. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef SEEN_EEK_COLOR_DEF_H -#define SEEN_EEK_COLOR_DEF_H - -#include -#include - -namespace eek -{ - -typedef void (*ColorCallback)( void* data ); - - -class ColorDef -{ -public: - ColorDef(); - ColorDef( unsigned int r, unsigned int g, unsigned int b, const std::string& description ); - virtual ~ColorDef(); - - ColorDef( ColorDef const &other ); - virtual ColorDef& operator=( ColorDef const &other ); - - void setRGB( unsigned int r, unsigned int g, unsigned int b ); - unsigned int getR() const { return r; } - unsigned int getG() const { return g; } - unsigned int getB() const { return b; } - - void addCallback( ColorCallback cb, void* data ); - void removeCallback( ColorCallback cb, void* data ); - - bool isEditable() const { return editable; } - void setEditable( bool edit ) { editable = edit; } - - std::string descr; - -protected: - unsigned int r; - unsigned int g; - unsigned int b; - bool none; - bool editable; - -private: - class HookData; - - std::vector _listeners; -}; - - -} // namespace eek - -#endif // SEEN_EEK_COLOR_DEF_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/eek-preview.cpp b/src/dialogs/eek-preview.cpp deleted file mode 100644 index 1c1adf543..000000000 --- a/src/dialogs/eek-preview.cpp +++ /dev/null @@ -1,736 +0,0 @@ -/** @file - * @brief EEK preview stuff - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Eek Preview Stuffs. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2005 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include "eek-preview.h" - -#define PRIME_BUTTON_MAGIC_NUMBER 1 - -#define FOCUS_PROP_ID 1 - -/* Keep in sycn with last value in eek-preview.h */ -#define PREVIEW_SIZE_LAST PREVIEW_SIZE_HUGE -#define PREVIEW_SIZE_NEXTFREE (PREVIEW_SIZE_HUGE + 1) - -#define PREVIEW_MAX_RATIO 500 - -static void eek_preview_class_init( EekPreviewClass *klass ); -static void eek_preview_init( EekPreview *preview ); - -static GtkWidgetClass* parent_class = 0; - -void eek_preview_set_color( EekPreview* preview, int r, int g, int b ) -{ - preview->_r = r; - preview->_g = g; - preview->_b = b; - - gtk_widget_queue_draw(GTK_WIDGET(preview)); -} - - -void eek_preview_set_pixbuf( EekPreview* preview, GdkPixbuf* pixbuf ) -{ - preview->_previewPixbuf = pixbuf; - - gtk_widget_queue_draw(GTK_WIDGET(preview)); - - if (preview->_scaled) { - g_object_unref(preview->_scaled); - preview->_scaled = 0; - } - preview->_scaledW = gdk_pixbuf_get_width(preview->_previewPixbuf); - preview->_scaledH = gdk_pixbuf_get_height(preview->_previewPixbuf); -} - - -GType eek_preview_get_type(void) -{ - static GType preview_type = 0; - - if (!preview_type) { - static const GTypeInfo preview_info = { - sizeof( EekPreviewClass ), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc)eek_preview_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof( EekPreview ), - 0, /* n_preallocs */ - (GInstanceInitFunc)eek_preview_init, - NULL /* value_table */ - }; - - - preview_type = g_type_register_static( GTK_TYPE_DRAWING_AREA, "EekPreview", &preview_info, (GTypeFlags)0 ); - } - - return preview_type; -} - -static gboolean setupDone = FALSE; -static GtkRequisition sizeThings[PREVIEW_SIZE_NEXTFREE]; - -void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes ) -{ - gint width = 0; - gint height = 0; - gint smallest = 512; - gint largest = 0; - guint i = 0; - guint delta = 0; - - for ( i = 0; i < count; ++i ) { - gboolean worked = gtk_icon_size_lookup( sizes[i], &width, &height ); - if ( worked ) { - if ( width < smallest ) { - smallest = width; - } - if ( width > largest ) { - largest = width; - } - } - } - - smallest = (smallest * 3) / 4; - - delta = largest - smallest; - - for ( i = 0; i < G_N_ELEMENTS(sizeThings); ++i ) { - guint val = smallest + ( (i * delta) / (G_N_ELEMENTS(sizeThings) - 1) ); - sizeThings[i].width = val; - sizeThings[i].height = val; - } - - setupDone = TRUE; -} - -static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req ) -{ - gint width = 0; - gint height = 0; - EekPreview* preview = EEK_PREVIEW(widget); - - if ( !setupDone ) { - GtkIconSize sizes[] = { - GTK_ICON_SIZE_MENU, - GTK_ICON_SIZE_SMALL_TOOLBAR, - GTK_ICON_SIZE_LARGE_TOOLBAR, - GTK_ICON_SIZE_BUTTON, - GTK_ICON_SIZE_DIALOG - }; - eek_preview_set_size_mappings( G_N_ELEMENTS(sizes), sizes ); - } - - width = sizeThings[preview->_size].width; - height = sizeThings[preview->_size].height; - - if ( preview->_view == VIEW_TYPE_LIST ) { - width *= 3; - } - - if ( preview->_ratio != 100 ) { - width = (width * preview->_ratio) / 100; - if ( width < 0 ) { - width = 1; - } - } - - req->width = width; - req->height = height; -} - -enum { - CLICKED_SIGNAL, - ALTCLICKED_SIGNAL, - LAST_SIGNAL -}; - - -static guint eek_preview_signals[LAST_SIGNAL] = { 0 }; - - -gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event ) -{ -/* g_message("Exposed!!! %s", GTK_WIDGET_HAS_FOCUS(widget) ? "XXX" : "---" ); */ - gint insetX = 0; - gint insetY = 0; - - (void)event; -/* - gint lower = widget->allocation.width; - lower = (widget->allocation.height < lower) ? widget->allocation.height : lower; - if ( lower > 16 ) { - insetX++; - if ( lower > 18 ) { - insetX++; - if ( lower > 22 ) { - insetX++; - if ( lower > 24 ) { - insetX++; - if ( lower > 32 ) { - insetX++; - } - } - } - } - insetY = insetX; - } -*/ - - if ( GTK_WIDGET_DRAWABLE( widget ) ) { - GtkStyle* style = gtk_widget_get_style( widget ); - - if ( insetX > 0 || insetY > 0 ) { - gtk_paint_flat_box( style, - widget->window, - (GtkStateType)GTK_WIDGET_STATE(widget), - GTK_SHADOW_NONE, - NULL, - widget, - NULL, - 0, 0, - widget->allocation.width, widget->allocation.height); - } - - GdkGC *gc = gdk_gc_new( widget->window ); - EekPreview* preview = EEK_PREVIEW(widget); - GdkColor fg = {0, preview->_r, preview->_g, preview->_b}; - - gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE ); - - gdk_gc_set_foreground( gc, &fg ); - - gdk_draw_rectangle( widget->window, - gc, - TRUE, - insetX, insetY, - widget->allocation.width - (insetX * 2), widget->allocation.height - (insetY * 2) ); - - if ( preview->_linked ) { - /* Draw arrow */ - GdkRectangle possible = {insetX, insetY, (widget->allocation.width - (insetX * 2)), (widget->allocation.height - (insetY * 2)) }; - GdkRectangle area = {possible.x, possible.y, possible.width / 2, possible.height / 2 }; - - /* Make it square */ - if ( area.width > area.height ) - area.width = area.height; - if ( area.height > area.width ) - area.height = area.width; - - /* Center it horizontally */ - if ( area.width < possible.width ) { - int diff = (possible.width - area.width) / 2; - area.x += diff; - } - - - if ( preview->_linked & PREVIEW_LINK_IN ) { - gtk_paint_arrow( style, - widget->window, - (GtkStateType)widget->state, - GTK_SHADOW_ETCHED_IN, - NULL, /* clip area. &area, */ - widget, /* may be NULL */ - NULL, /* detail */ - GTK_ARROW_DOWN, - FALSE, - area.x, area.y, - area.width, area.height - ); - } - - if ( preview->_linked & PREVIEW_LINK_OUT ) { - GdkRectangle otherArea = {area.x, area.y, area.width, area.height}; - if ( otherArea.height < possible.height ) { - otherArea.y = possible.y + (possible.height - otherArea.height); - } - - gtk_paint_arrow( style, - widget->window, - (GtkStateType)widget->state, - GTK_SHADOW_ETCHED_OUT, - NULL, /* clip area. &area, */ - widget, /* may be NULL */ - NULL, /* detail */ - GTK_ARROW_UP, - FALSE, - otherArea.x, otherArea.y, - otherArea.width, otherArea.height - ); - } - - if ( preview->_linked & PREVIEW_LINK_OTHER ) { - GdkRectangle otherArea = {insetX, area.y, area.width, area.height}; - if ( otherArea.height < possible.height ) { - otherArea.y = possible.y + (possible.height - otherArea.height) / 2; - } - - gtk_paint_arrow( style, - widget->window, - (GtkStateType)widget->state, - GTK_SHADOW_ETCHED_OUT, - NULL, /* clip area. &area, */ - widget, /* may be NULL */ - NULL, /* detail */ - GTK_ARROW_LEFT, - FALSE, - otherArea.x, otherArea.y, - otherArea.width, otherArea.height - ); - } - } - - if ( preview->_previewPixbuf ) { - GtkDrawingArea* da = &(preview->drawing); - GdkDrawable* drawable = (GdkDrawable*) (((GtkWidget*)da)->window); - gint w = 0; - gint h = 0; - gdk_drawable_get_size(drawable, &w, &h); - if ((w != preview->_scaledW) || (h != preview->_scaledH)) { - if (preview->_scaled) { - g_object_unref(preview->_scaled); - } - preview->_scaled = gdk_pixbuf_scale_simple(preview->_previewPixbuf, w, h, GDK_INTERP_BILINEAR); - preview->_scaledW = w; - preview->_scaledH = h; - } - - GdkPixbuf* pix = (preview->_scaled) ? preview->_scaled : preview->_previewPixbuf; - gdk_draw_pixbuf( drawable, 0, pix, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0 ); - } - - - if ( GTK_WIDGET_HAS_FOCUS(widget) ) { - gtk_paint_focus( style, - widget->window, - GTK_STATE_NORMAL, - NULL, /* GdkRectangle *area, */ - widget, - NULL, - 0 + 1, 0 + 1, - widget->allocation.width - 2, widget->allocation.height - 2 ); - } - } - - - return FALSE; -} - - -static gboolean eek_preview_enter_cb( GtkWidget* widget, GdkEventCrossing* event ) -{ - if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { - EekPreview* preview = EEK_PREVIEW(widget); - preview->_within = TRUE; - gtk_widget_set_state( widget, preview->_hot ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT ); - } - return FALSE; -} - -static gboolean eek_preview_leave_cb( GtkWidget* widget, GdkEventCrossing* event ) -{ - if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { - EekPreview* preview = EEK_PREVIEW(widget); - preview->_within = FALSE; - gtk_widget_set_state( widget, GTK_STATE_NORMAL ); - } - return FALSE; -} - -/* -static gboolean eek_preview_focus_in_event( GtkWidget* widget, GdkEventFocus* event ) -{ - g_message("focus IN"); - gboolean blip = parent_class->focus_in_event ? parent_class->focus_in_event(widget, event) : FALSE; - return blip; -} - -static gboolean eek_preview_focus_out_event( GtkWidget* widget, GdkEventFocus* event ) -{ - g_message("focus OUT"); - gboolean blip = parent_class->focus_out_event ? parent_class->focus_out_event(widget, event) : FALSE; - return blip; -} -*/ - -static gboolean eek_preview_button_press_cb( GtkWidget* widget, GdkEventButton* event ) -{ - if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { - EekPreview* preview = EEK_PREVIEW(widget); - - if ( preview->_takesFocus && !GTK_WIDGET_HAS_FOCUS(widget) ) { - gtk_widget_grab_focus(widget); - } - - if ( event->button == PRIME_BUTTON_MAGIC_NUMBER ) { - preview->_hot = TRUE; - if ( preview->_within ) { - gtk_widget_set_state( widget, GTK_STATE_ACTIVE ); - } - } - } - - return FALSE; -} - -static gboolean eek_preview_button_release_cb( GtkWidget* widget, GdkEventButton* event ) -{ - if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { - EekPreview* preview = EEK_PREVIEW(widget); - preview->_hot = FALSE; - gtk_widget_set_state( widget, GTK_STATE_NORMAL ); - if ( preview->_within && event->button == PRIME_BUTTON_MAGIC_NUMBER ) { - gboolean isAlt = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; - - if ( isAlt ) { - g_signal_emit( widget, eek_preview_signals[ALTCLICKED_SIGNAL], 0, 2 ); - } else { - g_signal_emit( widget, eek_preview_signals[CLICKED_SIGNAL], 0 ); - } - } - } - return FALSE; -} - -gboolean eek_preview_key_press_event( GtkWidget* widget, GdkEventKey* event) -{ - (void)widget; - (void)event; - g_message("TICK"); - return FALSE; -} - -gboolean eek_preview_key_release_event( GtkWidget* widget, GdkEventKey* event) -{ - (void)widget; - (void)event; - g_message("tock"); - return FALSE; -} - -static void eek_preview_get_property( GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class); - switch ( property_id ) { - case FOCUS_PROP_ID: - { - EekPreview* preview = EEK_PREVIEW( object ); - g_value_set_boolean( value, preview->_takesFocus ); - } - break; - default: - { - if ( gobjClass->get_property ) { - gobjClass->get_property( object, property_id, value, pspec ); - } - } - } -} - -static void eek_preview_set_property( GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class); - switch ( property_id ) { - case FOCUS_PROP_ID: - { - EekPreview* preview = EEK_PREVIEW( object ); - gboolean val = g_value_get_boolean( value ); - if ( val != preview->_takesFocus ) { - preview->_takesFocus = val; - } - } - break; - default: - { - if ( gobjClass->set_property ) { - gobjClass->set_property( object, property_id, value, pspec ); - } - } - } -} - - -static gboolean eek_preview_popup_menu( GtkWidget* widget ) -{ -/* g_message("Do the popup!"); */ - gboolean blip = parent_class->popup_menu ? parent_class->popup_menu(widget) : FALSE; - return blip; -} - - -static void eek_preview_class_init( EekPreviewClass *klass ) -{ - GObjectClass* gobjClass = G_OBJECT_CLASS(klass); - /*GtkObjectClass* objectClass = (GtkObjectClass*)klass;*/ - GtkWidgetClass* widgetClass = (GtkWidgetClass*)klass; - - gobjClass->set_property = eek_preview_set_property; - gobjClass->get_property = eek_preview_get_property; - - /*objectClass->destroy = eek_preview_destroy;*/ - - parent_class = (GtkWidgetClass*)g_type_class_peek_parent( klass ); - - /*widgetClass->map = ;*/ - /*widgetClass->unmap = ;*/ - /*widgetClass->realize = ;*/ - /*widgetClass->unrealize = ;*/ - widgetClass->size_request = eek_preview_size_request; - /*widgetClass->size_allocate = ;*/ - /*widgetClass->state_changed = ;*/ - /*widgetClass->style_set = ;*/ - /*widgetClass->grab_notify = ;*/ - - widgetClass->button_press_event = eek_preview_button_press_cb; - widgetClass->button_release_event = eek_preview_button_release_cb; - /*widgetClass->delete_event = ;*/ - /*widgetClass->destroy_event = ;*/ - widgetClass->expose_event = eek_preview_expose_event; -/* widgetClass->key_press_event = eek_preview_key_press_event; */ -/* widgetClass->key_release_event = eek_preview_key_release_event; */ - widgetClass->enter_notify_event = eek_preview_enter_cb; - widgetClass->leave_notify_event = eek_preview_leave_cb; - /*widgetClass->configure_event = ;*/ - /*widgetClass->focus_in_event = eek_preview_focus_in_event;*/ - /*widgetClass->focus_out_event = eek_preview_focus_out_event;*/ - - /* selection */ - /*widgetClass->selection_get = ;*/ - /*widgetClass->selection_received = ;*/ - - - /* drag source: */ - /*widgetClass->drag_begin = ;*/ - /*widgetClass->drag_end = ;*/ - /*widgetClass->drag_data_get = ;*/ - /*widgetClass->drag_data_delete = ;*/ - - /* drag target: */ - /*widgetClass->drag_leave = ;*/ - /*widgetClass->drag_motion = ;*/ - /*widgetClass->drag_drop = ;*/ - /*widgetClass->drag_data_received = ;*/ - - /* For keybindings: */ - widgetClass->popup_menu = eek_preview_popup_menu; - /*widgetClass->show_help = ;*/ - - /* Accessibility support: */ - /*widgetClass->get_accessible = ;*/ - /*widgetClass->screen_changed = ;*/ - /*widgetClass->can_activate_accel = ;*/ - - - eek_preview_signals[CLICKED_SIGNAL] = - g_signal_new( "clicked", - G_TYPE_FROM_CLASS( klass ), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), - G_STRUCT_OFFSET( EekPreviewClass, clicked ), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); - - eek_preview_signals[ALTCLICKED_SIGNAL] = - g_signal_new( "alt-clicked", - G_TYPE_FROM_CLASS( klass ), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), - G_STRUCT_OFFSET( EekPreviewClass, clicked ), - NULL, NULL, - g_cclosure_marshal_VOID__INT, G_TYPE_NONE, - 1, G_TYPE_INT ); - - - g_object_class_install_property( gobjClass, - FOCUS_PROP_ID, - g_param_spec_boolean( - "focus-on-click", - NULL, - "flag to grab focus when clicked", - TRUE, - (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT) - ) - ); -} - -void eek_preview_set_linked( EekPreview* splat, LinkType link ) -{ - link = (LinkType)(link & PREVIEW_LINK_ALL); - if ( link != (LinkType)splat->_linked ) { - splat->_linked = link; - - gtk_widget_queue_draw( GTK_WIDGET(splat) ); - } -} - -LinkType eek_preview_get_linked( EekPreview* splat ) -{ - return (LinkType)splat->_linked; -} - -gboolean eek_preview_get_focus_on_click( EekPreview* preview ) -{ - return preview->_takesFocus; -} - -void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click ) -{ - if ( focus_on_click != preview->_takesFocus ) { - preview->_takesFocus = focus_on_click; - } -} - -void eek_preview_set_details( EekPreview* preview, PreviewStyle prevstyle, ViewType view, PreviewSize size, guint ratio ) -{ - preview->_prevstyle = prevstyle; - preview->_view = view; - - if ( size > PREVIEW_SIZE_LAST ) { - size = PREVIEW_SIZE_LAST; - } - preview->_size = size; - - if ( ratio > PREVIEW_MAX_RATIO ) { - ratio = PREVIEW_MAX_RATIO; - } - preview->_ratio = ratio; - - gtk_widget_queue_draw(GTK_WIDGET(preview)); -} - -static void eek_preview_init( EekPreview *preview ) -{ - GtkWidget* widg = GTK_WIDGET(preview); - GTK_WIDGET_SET_FLAGS( widg, GTK_CAN_FOCUS ); - GTK_WIDGET_SET_FLAGS( widg, GTK_RECEIVES_DEFAULT ); - - gtk_widget_set_sensitive( widg, TRUE ); - - gtk_widget_add_events(widg, GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_KEY_PRESS_MASK - | GDK_KEY_RELEASE_MASK - | GDK_FOCUS_CHANGE_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK ); - -/* gtk_widget_add_events( widg, GDK_ALL_EVENTS_MASK );*/ - - preview->_r = 0x80; - preview->_g = 0x80; - preview->_b = 0xcc; - preview->_scaledW = 0; - preview->_scaledH = 0; - - preview->_hot = FALSE; - preview->_within = FALSE; - preview->_takesFocus = FALSE; - - preview->_prevstyle = PREVIEW_STYLE_ICON; - preview->_view = VIEW_TYPE_LIST; - preview->_size = PREVIEW_SIZE_SMALL; - preview->_ratio = 100; - - preview->_previewPixbuf = 0; - preview->_scaled = 0; - -/* - GdkColor color = {0}; - color.red = (255 << 8) | 255; - - GdkColor whack = {0}; - whack.green = (255 << 8) | 255; - - gtk_widget_modify_bg( widg, GTK_STATE_NORMAL, &color ); - gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &whack ); -*/ - -/* GTK_STATE_ACTIVE, */ -/* GTK_STATE_PRELIGHT, */ -/* GTK_STATE_SELECTED, */ -/* GTK_STATE_INSENSITIVE */ - - if ( 0 ) { - GdkColor color = {0,0,0,0}; - - color.red = 0xffff; - color.green = 0; - color.blue = 0xffff; - gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); - gtk_widget_modify_bg(widg, GTK_STATE_ACTIVE, &color); - - color.red = 0; - color.green = 0xffff; - color.blue = 0; - gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); - gtk_widget_modify_bg(widg, GTK_STATE_SELECTED, &color); - - color.red = 0xffff; - color.green = 0; - color.blue = 0; - gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); - gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &color ); - } -} - - -GtkWidget* eek_preview_new(void) -{ - return GTK_WIDGET( g_object_new( EEK_PREVIEW_TYPE, NULL ) ); -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/eek-preview.h b/src/dialogs/eek-preview.h deleted file mode 100644 index 6eb5c8930..000000000 --- a/src/dialogs/eek-preview.h +++ /dev/null @@ -1,152 +0,0 @@ -/** @file - * @brief EEK preview stuff - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Eek Preview Stuffs. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2005-2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef SEEN_EEK_PREVIEW_H -#define SEEN_EEK_PREVIEW_H - -#include -#include - -G_BEGIN_DECLS - - -#define EEK_PREVIEW_TYPE (eek_preview_get_type()) -#define EEK_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST( (obj), EEK_PREVIEW_TYPE, EekPreview)) -#define EEK_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST( (klass), EEK_PREVIEW_TYPE, EekPreviewClass)) -#define IS_EEK_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE( (obj), EEK_PREVIEW_TYPE)) -#define IS_EEK_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE( (klass), EEK_PREVIEW_TYPE)) -#define EEK_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS( (obj), EEK_PREVIEW_TYPE, EekPreviewClass)) - -typedef enum { - PREVIEW_STYLE_ICON = 0, - PREVIEW_STYLE_PREVIEW, - PREVIEW_STYLE_NAME, - PREVIEW_STYLE_BLURB, - PREVIEW_STYLE_ICON_NAME, - PREVIEW_STYLE_ICON_BLURB, - PREVIEW_STYLE_PREVIEW_NAME, - PREVIEW_STYLE_PREVIEW_BLURB -} PreviewStyle; - -typedef enum { - VIEW_TYPE_LIST = 0, - VIEW_TYPE_GRID -} ViewType; - -typedef enum { - PREVIEW_SIZE_TINY = 0, - PREVIEW_SIZE_SMALL, - PREVIEW_SIZE_MEDIUM, - PREVIEW_SIZE_BIG, - PREVIEW_SIZE_BIGGER, - PREVIEW_SIZE_HUGE -} PreviewSize; - -typedef enum { - PREVIEW_LINK_NONE = 0, - PREVIEW_LINK_IN = 1, - PREVIEW_LINK_OUT = 2, - PREVIEW_LINK_OTHER = 4, - PREVIEW_LINK_ALL = 7 -} LinkType; - -typedef struct _EekPreview EekPreview; -typedef struct _EekPreviewClass EekPreviewClass; - - -struct _EekPreview -{ - GtkDrawingArea drawing; - - int _r; - int _g; - int _b; - int _scaledW; - int _scaledH; - - gboolean _hot; - gboolean _within; - gboolean _takesFocus; - - PreviewStyle _prevstyle; - ViewType _view; - PreviewSize _size; - guint _ratio; - guint _linked; - GdkPixbuf* _previewPixbuf; - GdkPixbuf* _scaled; -}; - -struct _EekPreviewClass -{ - GtkDrawingAreaClass parent_class; - - void (*clicked) (EekPreview* splat); -}; - - -GType eek_preview_get_type(void) G_GNUC_CONST; -GtkWidget* eek_preview_new(void); - -void eek_preview_set_details( EekPreview* splat, PreviewStyle prevstyle, ViewType view, PreviewSize size, guint ratio ); -void eek_preview_set_color( EekPreview* splat, int r, int g, int b ); -void eek_preview_set_pixbuf( EekPreview* splat, GdkPixbuf* pixbuf ); - -void eek_preview_set_linked( EekPreview* splat, LinkType link ); -LinkType eek_preview_get_linked( EekPreview* splat ); - -gboolean eek_preview_get_focus_on_click( EekPreview* preview ); -void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click ); - -void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes ); - -G_END_DECLS - -#endif /* SEEN_EEK_PREVIEW_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/extensions.cpp b/src/dialogs/extensions.cpp deleted file mode 100644 index f168da33a..000000000 --- a/src/dialogs/extensions.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/** @file - * @brief A simple dialog with information about extensions - */ -/* Authors: - * Jon A. Cruz - * - * Copyright (C) 2005 Jon A. Cruz - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include //for GTK_RESPONSE* types -#include - -#include "extension/db.h" -#include "extensions.h" - - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -using Inkscape::Extension::Extension; - -ExtensionsPanel &ExtensionsPanel::getInstance() -{ - ExtensionsPanel &instance = *new ExtensionsPanel(); - - instance.rescan(); - - return instance; -} - - - -/** - * Constructor - */ -ExtensionsPanel::ExtensionsPanel() : - _showAll(false) -{ - Gtk::ScrolledWindow* scroller = new Gtk::ScrolledWindow(); - - _view.set_editable(false); - - scroller->add(_view); - add(*scroller); - - rescan(); - - show_all_children(); -} - -void ExtensionsPanel::set_full(bool full) -{ - if ( full != _showAll ) { - _showAll = full; - rescan(); - } -} - -void ExtensionsPanel::listCB( Inkscape::Extension::Extension * in_plug, gpointer in_data ) -{ - ExtensionsPanel * self = (ExtensionsPanel*)in_data; - - const char* stateStr; - Extension::state_t state = in_plug->get_state(); - switch ( state ) { - case Extension::STATE_LOADED: - { - stateStr = "loaded"; - } - break; - case Extension::STATE_UNLOADED: - { - stateStr = "unloaded"; - } - break; - case Extension::STATE_DEACTIVATED: - { - stateStr = "deactivated"; - } - break; - default: - stateStr = "unknown"; - } - - if ( self->_showAll || in_plug->deactivated() ) { -// gchar* line = g_strdup_printf( " extension %c %c %s |%s|%s|", -// (in_plug->loaded() ? 'X' : '-'), -// (in_plug->deactivated() ? 'X' : '-'), -// stateStr, in_plug->get_id(), -// in_plug->get_name() ); - gchar* line = g_strdup_printf( "%s %s\n \"%s\"", stateStr, in_plug->get_name(), in_plug->get_id() ); - - self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), line ); - self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), "\n" ); - //g_message( "%s", line ); - } - - - - return; -} - -void ExtensionsPanel::rescan() -{ - _view.get_buffer()->set_text("Extensions:\n"); -// g_message("/------------------"); - - Inkscape::Extension::db.foreach(listCB, (gpointer)this); - -// g_message("\\------------------"); -} - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/extensions.h b/src/dialogs/extensions.h deleted file mode 100644 index 8b0fc2780..000000000 --- a/src/dialogs/extensions.h +++ /dev/null @@ -1,56 +0,0 @@ -/** @file - * A simple dialog with information about extensions - */ -/* Authors: - * Jon A. Cruz - * - * Copyright (C) 2005 The Inkscape Organization - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_EXTENSIONS_H -#define SEEN_EXTENSIONS_H - -#include -#include "ui/widget/panel.h" - -namespace Inkscape { -namespace Extension { -class Extension; -} -} - -namespace Inkscape { -namespace UI { -namespace Dialogs { - - -/** - * A panel that displays information about extensions. - */ -class ExtensionsPanel : public Inkscape::UI::Widget::Panel -{ -public: - ExtensionsPanel(); - - static ExtensionsPanel &getInstance(); - - void set_full(bool full); - -private: - ExtensionsPanel(ExtensionsPanel const &); // no copy - ExtensionsPanel &operator=(ExtensionsPanel const &); // no assign - - static void listCB(Inkscape::Extension::Extension *in_plug, gpointer in_data); - - void rescan(); - - bool _showAll; - Gtk::TextView _view; -}; - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - -#endif // SEEN_EXTENSIONS_H diff --git a/src/dialogs/fill-style.cpp b/src/dialogs/fill-style.cpp deleted file mode 100644 index 24e46f056..000000000 --- a/src/dialogs/fill-style.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/** @file - * @brief Fill style widget - */ -/* Authors: - * Lauris Kaplinski - * Frank Felfe - * bulia byak - * - * Copyright (C) 1999-2005 authors - * Copyright (C) 2001-2002 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define noSP_FS_VERBOSE - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include "desktop-handles.h" -#include "desktop-style.h" -#include "display/sp-canvas.h" -#include "document-private.h" -#include "gradient-chemistry.h" -#include "inkscape.h" -#include "selection.h" -#include "sp-linear-gradient.h" -#include "sp-pattern.h" -#include "sp-radial-gradient.h" -#include "style.h" -#include "widgets/paint-selector.h" -#include "widgets/sp-widget.h" -#include "xml/repr.h" - -#include "dialogs/fill-style.h" - - -// These can be deleted once we sort out the libart dependence. - -#define ART_WIND_RULE_NONZERO 0 - -static void sp_fill_style_widget_construct ( SPWidget *spw, - SPPaintSelector *psel ); - -static void sp_fill_style_widget_modify_selection ( SPWidget *spw, - Inkscape::Selection *selection, - guint flags, - SPPaintSelector *psel ); - -static void sp_fill_style_widget_change_subselection ( Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw ); - -static void sp_fill_style_widget_change_selection ( SPWidget *spw, - Inkscape::Selection *selection, - SPPaintSelector *psel ); - -static void sp_fill_style_widget_update (SPWidget *spw); - -static void sp_fill_style_widget_paint_mode_changed ( SPPaintSelector *psel, - SPPaintSelectorMode mode, - SPWidget *spw ); -static void sp_fill_style_widget_fillrule_changed ( SPPaintSelector *psel, - SPPaintSelectorFillRule mode, - SPWidget *spw ); - -static void sp_fill_style_widget_paint_dragged (SPPaintSelector *psel, SPWidget *spw ); -static void sp_fill_style_widget_paint_changed (SPPaintSelector *psel, SPWidget *spw ); - -GtkWidget * -sp_fill_style_widget_new (void) -{ - GtkWidget *spw = sp_widget_new_global (INKSCAPE); - - GtkWidget *vb = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vb); - gtk_container_add (GTK_CONTAINER (spw), vb); - - GtkWidget *psel = sp_paint_selector_new (true); // with fillrule selector - gtk_widget_show (psel); - gtk_box_pack_start (GTK_BOX (vb), psel, TRUE, TRUE, 0); - g_object_set_data (G_OBJECT (spw), "paint-selector", psel); - - g_signal_connect ( G_OBJECT (psel), "mode_changed", - G_CALLBACK (sp_fill_style_widget_paint_mode_changed), - spw ); - - g_signal_connect ( G_OBJECT (psel), "dragged", - G_CALLBACK (sp_fill_style_widget_paint_dragged), - spw ); - - g_signal_connect ( G_OBJECT (psel), "changed", - G_CALLBACK (sp_fill_style_widget_paint_changed), - spw ); - - g_signal_connect ( G_OBJECT (psel), "fillrule_changed", - G_CALLBACK (sp_fill_style_widget_fillrule_changed), - spw ); - - - g_signal_connect ( G_OBJECT (spw), "construct", - G_CALLBACK (sp_fill_style_widget_construct), psel); - -//FIXME: switch these from spw signals to global inkscape object signals; spw just retranslates -//those anyway; then eliminate spw - g_signal_connect ( G_OBJECT (spw), "modify_selection", - G_CALLBACK (sp_fill_style_widget_modify_selection), psel); - - g_signal_connect ( G_OBJECT (spw), "change_selection", - G_CALLBACK (sp_fill_style_widget_change_selection), psel); - - g_signal_connect (INKSCAPE, "change_subselection", G_CALLBACK (sp_fill_style_widget_change_subselection), spw); - - sp_fill_style_widget_update (SP_WIDGET (spw)); - - return spw; - -} // end of sp_fill_style_widget_new() - - - -static void -sp_fill_style_widget_construct( SPWidget *spw, SPPaintSelector */*psel*/ ) -{ -#ifdef SP_FS_VERBOSE - g_print ( "Fill style widget constructed: inkscape %p repr %p\n", - spw->inkscape, spw->repr ); -#endif - if (spw->inkscape) { - sp_fill_style_widget_update (spw); - } - -} // end of sp_fill_style_widget_construct() - -static void -sp_fill_style_widget_modify_selection( SPWidget *spw, - Inkscape::Selection */*selection*/, - guint flags, - SPPaintSelector */*psel*/ ) -{ - if (flags & ( SP_OBJECT_MODIFIED_FLAG | - SP_OBJECT_PARENT_MODIFIED_FLAG | - SP_OBJECT_STYLE_MODIFIED_FLAG) ) - { - sp_fill_style_widget_update (spw); - } -} - -static void -sp_fill_style_widget_change_subselection( Inkscape::Application */*inkscape*/, - SPDesktop */*desktop*/, - SPWidget *spw ) -{ - sp_fill_style_widget_update (spw); -} - -static void -sp_fill_style_widget_change_selection( SPWidget *spw, - Inkscape::Selection */*selection*/, - SPPaintSelector */*psel*/ ) -{ - sp_fill_style_widget_update (spw); -} - -/** -* \param sel Selection to use, or NULL. -*/ -static void -sp_fill_style_widget_update (SPWidget *spw) -{ - if (g_object_get_data (G_OBJECT (spw), "update")) - return; - - if (g_object_get_data (G_OBJECT (spw), "local")) { - g_object_set_data (G_OBJECT (spw), "local", GINT_TO_POINTER (FALSE)); // local change; do nothing, but reset the flag - return; - } - - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); - - SPPaintSelector *psel = SP_PAINT_SELECTOR (g_object_get_data (G_OBJECT (spw), "paint-selector")); - - // create temporary style - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection - int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FILL); - - switch (result) { - case QUERY_STYLE_NOTHING: - { - /* No paint at all */ - sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_EMPTY); - break; - } - - case QUERY_STYLE_SINGLE: - case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector - case QUERY_STYLE_MULTIPLE_SAME: - { - SPPaintSelectorMode pselmode = sp_style_determine_paint_selector_mode (query, true); - sp_paint_selector_set_mode (psel, pselmode); - - sp_paint_selector_set_fillrule (psel, query->fill_rule.computed == ART_WIND_RULE_NONZERO? - SP_PAINT_SELECTOR_FILLRULE_NONZERO : SP_PAINT_SELECTOR_FILLRULE_EVENODD); - - if (query->fill.set && query->fill.isColor()) { - sp_paint_selector_set_color_alpha (psel, &query->fill.value.color, SP_SCALE24_TO_FLOAT (query->fill_opacity.value)); - } else if (query->fill.set && query->fill.isPaintserver()) { - - SPPaintServer *server = SP_STYLE_FILL_SERVER (query); - - if (SP_IS_LINEARGRADIENT (server)) { - SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); - sp_paint_selector_set_gradient_linear (psel, vector); - - SPLinearGradient *lg = SP_LINEARGRADIENT (server); - sp_paint_selector_set_gradient_properties (psel, - SP_GRADIENT_UNITS (lg), - SP_GRADIENT_SPREAD (lg)); - } else if (SP_IS_RADIALGRADIENT (server)) { - SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); - sp_paint_selector_set_gradient_radial (psel, vector); - - SPRadialGradient *rg = SP_RADIALGRADIENT (server); - sp_paint_selector_set_gradient_properties (psel, - SP_GRADIENT_UNITS (rg), - SP_GRADIENT_SPREAD (rg)); - } else if (SP_IS_PATTERN (server)) { - SPPattern *pat = pattern_getroot (SP_PATTERN (server)); - sp_update_pattern_list (psel, pat); - } - } - break; - } - - case QUERY_STYLE_MULTIPLE_DIFFERENT: - { - sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_MULTIPLE); - break; - } - } - - sp_style_unref(query); - - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); - -} - - -static void -sp_fill_style_widget_paint_mode_changed ( SPPaintSelector *psel, - SPPaintSelectorMode /*mode*/, - SPWidget *spw ) -{ - if (g_object_get_data (G_OBJECT (spw), "update")) - return; - - /* TODO: Does this work? */ - /* TODO: Not really, here we have to get old color back from object */ - /* Instead of relying on paint widget having meaningful colors set */ - sp_fill_style_widget_paint_changed (psel, spw); -} - -static void -sp_fill_style_widget_fillrule_changed ( SPPaintSelector */*psel*/, - SPPaintSelectorFillRule mode, - SPWidget *spw ) -{ - if (g_object_get_data (G_OBJECT (spw), "update")) - return; - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_set_property (css, "fill-rule", mode == SP_PAINT_SELECTOR_FILLRULE_EVENODD? "evenodd":"nonzero"); - - sp_desktop_set_style (desktop, css); - - sp_repr_css_attr_unref (css); - - sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_FILL_STROKE, - _("Change fill rule")); -} - -static gchar const *undo_label_1 = "fill:flatcolor:1"; -static gchar const *undo_label_2 = "fill:flatcolor:2"; -static gchar const *undo_label = undo_label_1; - -/** -This is called repeatedly while you are dragging a color slider, only for flat color -modes. Previously it set the color in style but did not update the repr for efficiency, however -this was flakey and didn't buy us almost anything. So now it does the same as _changed, except -lumps all its changes for undo. - */ -static void -sp_fill_style_widget_paint_dragged (SPPaintSelector *psel, SPWidget *spw) -{ - if (!spw->inkscape) { - return; - } - - if (g_object_get_data (G_OBJECT (spw), "update")) { - return; - } - - if (g_object_get_data (G_OBJECT (spw), "local")) { - // previous local flag not cleared yet; - // this means dragged events come too fast, so we better skip this one to speed up display - // (it's safe to do this in any case) - return; - } - - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); - - switch (psel->mode) { - - case SP_PAINT_SELECTOR_MODE_COLOR_RGB: - case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: - { - sp_paint_selector_set_flat_color (psel, SP_ACTIVE_DESKTOP, "fill", "fill-opacity"); - sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE, - _("Set fill color")); - g_object_set_data (G_OBJECT (spw), "local", GINT_TO_POINTER (TRUE)); // local change, do not update from selection - break; - } - - default: - g_warning ( "file %s: line %d: Paint %d should not emit 'dragged'", - __FILE__, __LINE__, psel->mode ); - break; - - } - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); -} - - -/** -This is called (at least) when: -1 paint selector mode is switched (e.g. flat color -> gradient) -2 you finished dragging a gradient node and released mouse -3 you changed a gradient selector parameter (e.g. spread) -Must update repr. - */ -static void -sp_fill_style_widget_paint_changed ( SPPaintSelector *psel, - SPWidget *spw ) -{ - if (g_object_get_data (G_OBJECT (spw), "update")) { - return; - } - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (!desktop) { - return; - } - SPDocument *document = sp_desktop_document (desktop); - Inkscape::Selection *selection = sp_desktop_selection (desktop); - - GSList const *items = selection->itemList(); - - switch (psel->mode) { - - case SP_PAINT_SELECTOR_MODE_EMPTY: - // This should not happen. - g_warning ( "file %s: line %d: Paint %d should not emit 'changed'", - __FILE__, __LINE__, psel->mode); - break; - case SP_PAINT_SELECTOR_MODE_MULTIPLE: - // This happens when you switch multiple objects with different gradients to flat color; - // nothing to do here. - break; - - case SP_PAINT_SELECTOR_MODE_NONE: - { - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_set_property (css, "fill", "none"); - - sp_desktop_set_style (desktop, css); - - sp_repr_css_attr_unref (css); - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Remove fill")); - break; - } - - case SP_PAINT_SELECTOR_MODE_COLOR_RGB: - case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: - { - // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in losing release events - sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0); - - sp_paint_selector_set_flat_color (psel, desktop, "fill", "fill-opacity"); - sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE, - _("Set fill color")); - // resume interruptibility - sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop)); - - // on release, toggle undo_label so that the next drag will not be lumped with this one - if (undo_label == undo_label_1) - undo_label = undo_label_2; - else - undo_label = undo_label_1; - - break; - } - - case SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR: - case SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL: - if (items) { - SPGradientType const gradient_type = ( psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR - ? SP_GRADIENT_TYPE_LINEAR - : SP_GRADIENT_TYPE_RADIAL ); - - // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property(css, "fill-opacity", "1.0"); - - SPGradient *vector = sp_paint_selector_get_gradient_vector(psel); - if (!vector) { - /* No vector in paint selector should mean that we just changed mode */ - - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result = objects_query_fillstroke ((GSList *) items, query, true); - guint32 common_rgb = 0; - if (result == QUERY_STYLE_MULTIPLE_SAME) { - if (!query->fill.isColor()) { - common_rgb = sp_desktop_get_color(desktop, true); - } else { - common_rgb = query->fill.value.color.toRGBA32( 0xff ); - } - vector = sp_document_default_gradient_vector(document, common_rgb); - } - sp_style_unref(query); - - for (GSList const *i = items; i != NULL; i = i->next) { - //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style"); - - if (!vector) { - sp_item_set_gradient(SP_ITEM(i->data), - sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), true), - gradient_type, true); - } else { - sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, true); - } - } - } else { - /* We have changed from another gradient type, or modified spread/units within - * this gradient type. */ - vector = sp_gradient_ensure_vector_normalized (vector); - for (GSList const *i = items; i != NULL; i = i->next) { - //FIXME: see above - sp_repr_css_change_recursive (SP_OBJECT_REPR (i->data), css, "style"); - - SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, true); - sp_gradient_selector_attrs_to_gradient (gr, psel); - } - } - - sp_repr_css_attr_unref (css); - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Set gradient on fill")); - } - break; - - case SP_PAINT_SELECTOR_MODE_PATTERN: - - if (items) { - - SPPattern *pattern = sp_paint_selector_get_pattern (psel); - if (!pattern) { - - /* No Pattern in paint selector should mean that we just - * changed mode - dont do jack. - */ - - } else { - Inkscape::XML::Node *patrepr = SP_OBJECT_REPR(pattern); - SPCSSAttr *css = sp_repr_css_attr_new (); - gchar *urltext = g_strdup_printf ("url(#%s)", patrepr->attribute("id")); - sp_repr_css_set_property (css, "fill", urltext); - - // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs - sp_repr_css_set_property(css, "fill-opacity", "1.0"); - - // cannot just call sp_desktop_set_style, because we don't want to touch those - // objects who already have the same root pattern but through a different href - // chain. FIXME: move this to a sp_item_set_pattern - for (GSList const *i = items; i != NULL; i = i->next) { - SPObject *selobj = SP_OBJECT (i->data); - - SPStyle *style = SP_OBJECT_STYLE (selobj); - if (style && style->fill.isPaintserver()) { - SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (selobj); - if (SP_IS_PATTERN (server) && pattern_getroot (SP_PATTERN(server)) == pattern) - // only if this object's pattern is not rooted in our selected pattern, apply - continue; - } - - sp_desktop_apply_css_recursive (selobj, css, true); - } - - sp_repr_css_attr_unref (css); - g_free (urltext); - - } // end if - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Set pattern on fill")); - - } // end if - - break; - - case SP_PAINT_SELECTOR_MODE_UNSET: - if (items) { - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_unset_property (css, "fill"); - - sp_desktop_set_style (desktop, css); - sp_repr_css_attr_unref (css); - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Unset fill")); - } - break; - - default: - g_warning ( "file %s: line %d: Paint selector should not be in " - "mode %d", - __FILE__, __LINE__, psel->mode ); - break; - } - - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/fill-style.h b/src/dialogs/fill-style.h deleted file mode 100644 index 3924412ec..000000000 --- a/src/dialogs/fill-style.h +++ /dev/null @@ -1,33 +0,0 @@ -/** @file - * @brief Fill style configuration - */ -/* Authors: - * Lauris Kaplinski - * - * Copyright (C) 2002 Lauris Kaplinski - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DIALOGS_SP_FILL_STYLE_H -#define SEEN_DIALOGS_SP_FILL_STYLE_H - -#include -#include -#include "forward.h" - - -GtkWidget *sp_fill_style_widget_new (void); - -#endif - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/guidelinedialog.cpp b/src/dialogs/guidelinedialog.cpp deleted file mode 100644 index f0115ee91..000000000 --- a/src/dialogs/guidelinedialog.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/** @file - * @brief Simple guideline dialog - */ -/* Authors: - * Lauris Kaplinski - * Andrius R. - * Johan Engelen - * - * Copyright (C) 1999-2007 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include -#endif -#include "display/guideline.h" -#include "helper/unit-menu.h" -#include "helper/units.h" -#include "desktop.h" -#include "document.h" -#include "sp-guide.h" -#include "sp-namedview.h" -#include "desktop-handles.h" -#include "event-context.h" -#include "widgets/desktop-widget.h" -#include "sp-metrics.h" -#include -#include "dialogs/dialog-events.h" -#include "message-context.h" -#include "xml/repr.h" -#include <2geom/point.h> -#include <2geom/angle.h> -#include "guidelinedialog.h" - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -GuidelinePropertiesDialog::GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop) -: _desktop(desktop), _guide(guide), - _label_units(_("Unit:")), - _label_X(_("X:")), - _label_Y(_("Y:")), - _label_degrees(_("Angle (degrees):")), - _relative_toggle(_("Rela_tive change"), _("Move and/or rotate the guide relative to current settings")), - _adjustment_x(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), - _adjustment_y(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), - _adj_angle(0.0, -360, 360, 1.0, 10.0, 10.0), - _unit_selector(NULL), _mode(true), _oldpos(0.,0.), _oldangle(0.0) -{ -} - -GuidelinePropertiesDialog::~GuidelinePropertiesDialog() { -} - -void GuidelinePropertiesDialog::showDialog(SPGuide *guide, SPDesktop *desktop) { - GuidelinePropertiesDialog dialog(guide, desktop); - dialog._setup(); - dialog.run(); -} - -void GuidelinePropertiesDialog::_modeChanged() -{ - _mode = !_relative_toggle.get_active(); - if (!_mode) { - // relative - _spin_angle.set_value(0); - - _spin_button_y.set_value(0); - _spin_button_x.set_value(0); - } else { - // absolute - _spin_angle.set_value(_oldangle); - - SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); - gdouble const val_y = sp_pixels_get_units(_oldpos[Geom::Y], unit); - _spin_button_y.set_value(val_y); - gdouble const val_x = sp_pixels_get_units(_oldpos[Geom::X], unit); - _spin_button_x.set_value(val_x); - } -} - -void GuidelinePropertiesDialog::_onApply() -{ - double deg_angle = _spin_angle.get_value(); - if (!_mode) - deg_angle += _oldangle; - Geom::Point normal; - if ( deg_angle == 90. || deg_angle == 270. || deg_angle == -90. || deg_angle == -270.) { - normal = Geom::Point(1.,0.); - } else if ( deg_angle == 0. || deg_angle == 180. || deg_angle == -180.) { - normal = Geom::Point(0.,1.); - } else { - double rad_angle = Geom::deg_to_rad( deg_angle ); - normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0)); - } - sp_guide_set_normal(*_guide, normal, true); - - SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); - gdouble const raw_dist_x = _spin_button_x.get_value(); - gdouble const points_x = sp_units_get_pixels(raw_dist_x, unit); - gdouble const raw_dist_y = _spin_button_y.get_value(); - gdouble const points_y = sp_units_get_pixels(raw_dist_y, unit); - Geom::Point newpos(points_x, points_y); - if (!_mode) - newpos += _oldpos; - - sp_guide_moveto(*_guide, newpos, true); - - sp_document_done(SP_OBJECT_DOCUMENT(_guide), SP_VERB_NONE, - _("Set guide properties")); -} - -void GuidelinePropertiesDialog::_onOK() -{ - _onApply(); -} - -void GuidelinePropertiesDialog::_onDelete() -{ - SPDocument *doc = SP_OBJECT_DOCUMENT(_guide); - sp_guide_remove(_guide); - sp_document_done(doc, SP_VERB_NONE, - _("Delete guide")); -} - -void GuidelinePropertiesDialog::_response(gint response) -{ - switch (response) { - case Gtk::RESPONSE_OK: - _onOK(); - break; - case -12: - _onDelete(); - break; - case Gtk::RESPONSE_CANCEL: - break; - case Gtk::RESPONSE_DELETE_EVENT: - break; -/* case GTK_RESPONSE_APPLY: - _onApply(); - break; -*/ - default: - g_assert_not_reached(); - } -} - -void GuidelinePropertiesDialog::_setup() { - set_title(_("Guideline")); - add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); - add_button(Gtk::Stock::DELETE, -12); - add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - - Gtk::VBox *mainVBox = get_vbox(); - - _layout_table.set_spacings(4); - _layout_table.resize (3, 4); - - mainVBox->pack_start(_layout_table, false, false, 0); - - _label_name.set_label("foo0"); - _layout_table.attach(_label_name, - 0, 3, 0, 1, Gtk::FILL, Gtk::FILL); - _label_name.set_alignment(0, 0.5); - - _label_descr.set_label("foo1"); - _layout_table.attach(_label_descr, - 0, 3, 1, 2, Gtk::FILL, Gtk::FILL); - _label_descr.set_alignment(0, 0.5); - - // indent - _layout_table.attach(*manage(new Gtk::Label(" ")), - 0, 1, 2, 3, Gtk::FILL, Gtk::FILL, 10); - - // mode radio button - _layout_table.attach(_relative_toggle, - 1, 3, 9, 10, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _relative_toggle.signal_toggled().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_modeChanged)); - - // unitmenu - /* fixme: We should allow percents here too, as percents of the canvas size */ - GtkWidget *unit_selector = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); - sp_unit_selector_set_unit(SP_UNIT_SELECTOR(unit_selector), _desktop->namedview->doc_units); - _unit_selector = Gtk::manage(Glib::wrap(unit_selector)); - - // position spinbuttons - sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_x.gobj())); - sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_y.gobj())); - _spin_button_x.configure(_adjustment_x, 1.0 , 3); - _spin_button_x.set_numeric(); - _spin_button_y.configure(_adjustment_y, 1.0 , 3); - _spin_button_y.set_numeric(); - _layout_table.attach(_label_X, - 1, 2, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _layout_table.attach(_spin_button_x, - 2, 3, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _layout_table.attach(_label_Y, - 1, 2, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _layout_table.attach(_spin_button_y, - 2, 3, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - gtk_signal_connect_object(GTK_OBJECT(_spin_button_x.gobj()), "activate", - GTK_SIGNAL_FUNC(gtk_window_activate_default), - gobj()); - - _layout_table.attach(_label_units, - 1, 2, 6, 7, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _layout_table.attach(*_unit_selector, - 2, 3, 6, 7, Gtk::FILL, Gtk::FILL); - - // angle spinbutton - _spin_angle.configure(_adj_angle, 5.0 , 3); - _spin_angle.set_numeric(); - _spin_angle.show(); - _layout_table.attach(_label_degrees, - 1, 2, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - _layout_table.attach(_spin_angle, - 2, 3, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); - - - // dialog - set_default_response(Gtk::RESPONSE_OK); - signal_response().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_response)); - - // initialize dialog - _oldpos = _guide->point_on_line; - if (_guide->is_vertical()) { - _oldangle = 90; - } else if (_guide->is_horizontal()) { - _oldangle = 0; - } else { - _oldangle = Geom::rad_to_deg( std::atan2( - _guide->normal_to_line[Geom::X], _guide->normal_to_line[Geom::Y] ) ); - } - - { - Inkscape::XML::Node *repr = SP_OBJECT_REPR (_guide); - const gchar *guide_id = repr->attribute("id"); - gchar *label = g_strdup_printf(_("Guideline ID: %s"), guide_id); - _label_name.set_label(label); - g_free(label); - } - { - gchar *guide_description = sp_guide_description(_guide); - gchar *label = g_strdup_printf(_("Current: %s"), guide_description); - g_free(guide_description); - _label_descr.set_markup(label); - g_free(label); - } - - _modeChanged(); // sets values of spinboxes. - - if ( _oldangle == 90. || _oldangle == 270. || _oldangle == -90. || _oldangle == -270.) { - _spin_button_x.grab_focus(); - _spin_button_x.select_region(0, 20); - } else if ( _oldangle == 0. || _oldangle == 180. || _oldangle == -180.) { - _spin_button_y.grab_focus(); - _spin_button_y.select_region(0, 20); - } else { - _spin_angle.grab_focus(); - _spin_angle.select_region(0, 20); - } - - set_position(Gtk::WIN_POS_MOUSE); - - show_all_children(); - set_modal(true); - _desktop->setWindowTransient (gobj()); - property_destroy_with_parent() = true; -} - -} -} -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/guidelinedialog.h b/src/dialogs/guidelinedialog.h deleted file mode 100644 index 49f94deea..000000000 --- a/src/dialogs/guidelinedialog.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * - * \brief Dialog for modifying guidelines - * - * Author: - * Andrius R. - * Johan Engelen - * - * Copyright (C) 2006-2007 Authors - * - * Released under GNU GPL. Read the file 'COPYING' for more information - */ - -#ifndef INKSCAPE_DIALOG_GUIDELINE_H -#define INKSCAPE_DIALOG_GUIDELINE_H - -#include -#include -#include -#include -#include -#include -#include "ui/widget/button.h" -#include <2geom/point.h> - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -class GuidelinePropertiesDialog : public Gtk::Dialog { -public: - GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop); - virtual ~GuidelinePropertiesDialog(); - - Glib::ustring getName() const { return "GuidelinePropertiesDialog"; } - - static void showDialog(SPGuide *guide, SPDesktop *desktop); - -protected: - void _setup(); - - void _onApply(); - void _onOK(); - void _onDelete(); - - void _response(gint response); - void _modeChanged(); - -private: - GuidelinePropertiesDialog(GuidelinePropertiesDialog const &); // no copy - GuidelinePropertiesDialog &operator=(GuidelinePropertiesDialog const &); // no assign - - SPDesktop *_desktop; - SPGuide *_guide; - Gtk::Table _layout_table; - Gtk::Label _label_name; - Gtk::Label _label_descr; - Gtk::Label _label_units; - Gtk::Label _label_X; - Gtk::Label _label_Y; - Gtk::Label _label_degrees; - Inkscape::UI::Widget::CheckButton _relative_toggle; - Gtk::Adjustment _adjustment_x; - Gtk::SpinButton _spin_button_x; - Gtk::Adjustment _adjustment_y; - Gtk::SpinButton _spin_button_y; - - Gtk::Adjustment _adj_angle; - Gtk::SpinButton _spin_angle; - - Gtk::Widget *_unit_selector; - bool _mode; - Geom::Point _oldpos; - gdouble _oldangle; -}; - -} // namespace -} // namespace -} // namespace - - -#endif // INKSCAPE_DIALOG_GUIDELINE_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/iconpreview.cpp b/src/dialogs/iconpreview.cpp deleted file mode 100644 index 4d402d235..000000000 --- a/src/dialogs/iconpreview.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/** @file - * @brief A simple dialog for previewing icon representation. - */ -/* Authors: - * Jon A. Cruz - * Bob Jamison - * Other dudes from The Inkscape Organization - * - * Copyright (C) 2004 Bob Jamison - * Copyright (C) 2005 Jon A. Cruz - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "iconpreview.h" - -#include - -#include -#include //for GTK_RESPONSE* types -#include -#include -#include - -#include "preferences.h" -#include "inkscape.h" -#include "document.h" -#include "desktop-handles.h" -#include "selection.h" -#include "desktop.h" -#include "display/nr-arena.h" -#include "sp-root.h" -#include "xml/repr.h" - -extern "C" { -// takes doc, root, icon, and icon name to produce pixels -guchar * -sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, - const gchar *name, unsigned int psize ); -} - -namespace Inkscape { -namespace UI { -namespace Dialogs { - - -IconPreviewPanel& -IconPreviewPanel::getInstance() -{ - static IconPreviewPanel &instance = *new IconPreviewPanel(); - - instance.refreshPreview(); - - return instance; -} - -//######################################################################### -//## E V E N T S -//######################################################################### - -void IconPreviewPanel::on_button_clicked(int which) -{ - if ( hot != which ) { - buttons[hot]->set_active( false ); - - hot = which; - updateMagnify(); - _getContents()->queue_draw(); - } -} - - - - -//######################################################################### -//## C O N S T R U C T O R / D E S T R U C T O R -//######################################################################### -/** - * Constructor - */ -IconPreviewPanel::IconPreviewPanel() : - UI::Widget::Panel("", "/dialogs/iconpreview", SP_VERB_VIEW_ICON_PREVIEW), - hot(1), - refreshButton(0), - selectionButton(0) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - numEntries = 0; - - std::vector pref_sizes = prefs->getAllDirs("/iconpreview/sizes/default"); - std::vector rawSizes; - - for (std::vector::iterator i = pref_sizes.begin(); i != pref_sizes.end(); ++i) { - if (prefs->getBool(*i + "/show", true)) { - int sizeVal = prefs->getInt(*i + "/value", -1); - if (sizeVal > 0) { - rawSizes.push_back(sizeVal); - } - } - } - - if ( !rawSizes.empty() ) { - numEntries = rawSizes.size(); - sizes = new int[numEntries]; - int i = 0; - for ( std::vector::iterator it = rawSizes.begin(); it != rawSizes.end(); ++it, ++i ) { - sizes[i] = *it; - } - } - - if ( numEntries < 1 ) - { - numEntries = 5; - sizes = new int[numEntries]; - sizes[0] = 16; - sizes[1] = 24; - sizes[2] = 32; - sizes[3] = 48; - sizes[4] = 128; - } - - pixMem = new guchar*[numEntries]; - images = new Gtk::Image*[numEntries]; - labels = new Glib::ustring*[numEntries]; - buttons = new Gtk::ToggleToolButton*[numEntries]; - - - for ( int i = 0; i < numEntries; i++ ) { - char *label = g_strdup_printf(_("%d x %d"), sizes[i], sizes[i]); - labels[i] = new Glib::ustring(label); - g_free(label); - pixMem[i] = 0; - images[i] = 0; - } - - - magLabel.set_label( *labels[hot] ); - - Gtk::VBox* magBox = new Gtk::VBox(); - - magBox->pack_start( magnified ); - magBox->pack_start( magLabel, Gtk::PACK_SHRINK ); - - - Gtk::VBox * verts = new Gtk::VBox(); - for ( int i = 0; i < numEntries; i++ ) { - pixMem[i] = new guchar[4 * sizes[i] * sizes[i]]; - memset( pixMem[i], 0x00, 4 * sizes[i] * sizes[i] ); - - GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], sizes[i] * 4, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL ); - GtkImage* img = GTK_IMAGE( gtk_image_new_from_pixbuf( pb ) ); - images[i] = Glib::wrap(img); - Glib::ustring label(*labels[i]); - buttons[i] = new Gtk::ToggleToolButton(label); - buttons[i]->set_active( i == hot ); - buttons[i]->set_icon_widget(*images[i]); - - tips.set_tip((*buttons[i]), label); - - buttons[i]->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &IconPreviewPanel::on_button_clicked), i) ); - - - verts->add(*buttons[i]); - } - - iconBox.pack_start(splitter); - splitter.pack1( *magBox, true, true ); - splitter.pack2( *verts, false, false ); - - - //## The Refresh button - - - Gtk::HButtonBox* holder = new Gtk::HButtonBox( Gtk::BUTTONBOX_END ); - _getContents()->pack_end(*holder, false, false); - - selectionButton = new Gtk::ToggleButton(_("Selection")); // , GTK_RESPONSE_APPLY - holder->pack_start( *selectionButton, false, false ); - tips.set_tip((*selectionButton), _("Selection only or whole document")); - selectionButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::modeToggled) ); - - gint val = prefs->getBool("/iconpreview/selectionOnly"); - selectionButton->set_active( val != 0 ); - - refreshButton = new Gtk::Button(Gtk::Stock::REFRESH); // , GTK_RESPONSE_APPLY - holder->pack_end( *refreshButton, false, false ); - tips.set_tip((*refreshButton), _("Refresh the icons")); - refreshButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::refreshPreview) ); - - - _getContents()->pack_start(iconBox, Gtk::PACK_EXPAND_WIDGET); - - show_all_children(); -} - -//######################################################################### -//## M E T H O D S -//######################################################################### - - -void IconPreviewPanel::refreshPreview() -{ - SPDesktop *desktop = getDesktop(); - if ( desktop ) { - - if ( selectionButton && selectionButton->get_active() ) - { - Inkscape::Selection * sel = sp_desktop_selection(desktop); - if ( sel ) { - //g_message("found a selection to play with"); - - GSList const *items = sel->itemList(); - SPObject *target = 0; - while ( items && !target ) { - SPItem* item = SP_ITEM( items->data ); - SPObject * obj = SP_OBJECT(item); - gchar const *id = SP_OBJECT_ID( obj ); - if ( id ) { - target = obj; - } - - items = g_slist_next(items); - } - if ( target ) { - renderPreview(target); - } - } - } - else - { - SPObject *target = desktop->currentRoot(); - if ( target ) { - renderPreview(target); - } - } - } -} - -void IconPreviewPanel::modeToggled() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/iconpreview/selectionOnly", (selectionButton && selectionButton->get_active())); - - refreshPreview(); -} - -void IconPreviewPanel::renderPreview( SPObject* obj ) -{ - SPDocument * doc = SP_OBJECT_DOCUMENT(obj); - gchar * id = SP_OBJECT_ID(obj); - -// g_message(" setting up to render '%s' as the icon", id ); - - NRArenaItem *root = NULL; - - /* Create new arena */ - NRArena *arena = NRArena::create(); - - /* Create ArenaItem and set transform */ - unsigned int visionkey = sp_item_display_key_new(1); - - root = sp_item_invoke_show ( SP_ITEM( SP_DOCUMENT_ROOT(doc) ), - arena, visionkey, SP_ITEM_SHOW_DISPLAY ); - - for ( int i = 0; i < numEntries; i++ ) { - guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i] ); -// g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") ); - if ( px ) { - memcpy( pixMem[i], px, sizes[i] * sizes[i] * 4 ); - g_free( px ); - px = 0; - } else { - memset( pixMem[i], 0, sizes[i] * sizes[i] * 4 ); - } - images[i]->queue_draw(); - } - updateMagnify(); - - sp_item_invoke_hide(SP_ITEM(sp_document_root(doc)), visionkey); - nr_object_unref((NRObject *) arena); -} - -void IconPreviewPanel::updateMagnify() -{ - Glib::RefPtr buf = images[hot]->get_pixbuf()->scale_simple( 128, 128, Gdk::INTERP_NEAREST ); - magLabel.set_label( *labels[hot] ); - magnified.set( buf ); - magnified.queue_draw(); - magnified.get_parent()->queue_draw(); -} - - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/iconpreview.h b/src/dialogs/iconpreview.h deleted file mode 100644 index 8f143725d..000000000 --- a/src/dialogs/iconpreview.h +++ /dev/null @@ -1,84 +0,0 @@ -/** @file - * @brief A simple dialog for previewing icon representation. - */ -/* Authors: - * Jon A. Cruz - * Bob Jamison - * Other dudes from The Inkscape Organization - * - * Copyright (C) 2004,2005 The Inkscape Organization - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_ICON_PREVIEW_H -#define SEEN_ICON_PREVIEW_H - -#include -#include -#include -#include -#include -#include -#include - -#include "ui/widget/panel.h" - -struct SPObject; - -namespace Inkscape { -namespace UI { -namespace Dialogs { - - -/** - * A panel that displays an icon preview - */ -class IconPreviewPanel : public UI::Widget::Panel -{ -public: - IconPreviewPanel(); - //IconPreviewPanel(Glib::ustring const &label); - - static IconPreviewPanel& getInstance(); - - void refreshPreview(); - void modeToggled(); - -private: - IconPreviewPanel(IconPreviewPanel const &); // no copy - IconPreviewPanel &operator=(IconPreviewPanel const &); // no assign - - - void on_button_clicked(int which); - void renderPreview( SPObject* obj ); - void updateMagnify(); - - Gtk::Tooltips tips; - - Gtk::VBox iconBox; - Gtk::HPaned splitter; - - int hot; - int numEntries; - int* sizes; - - Gtk::Image magnified; - Gtk::Label magLabel; - - Gtk::Button *refreshButton; - Gtk::ToggleButton *selectionButton; - - guchar** pixMem; - Gtk::Image** images; - Glib::ustring** labels; - Gtk::ToggleToolButton** buttons; -}; - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - - -#endif // SEEN_ICON_PREVIEW_H diff --git a/src/dialogs/in-dt-coordsys.cpp b/src/dialogs/in-dt-coordsys.cpp deleted file mode 100644 index 54d9ac326..000000000 --- a/src/dialogs/in-dt-coordsys.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "sp-root.h" - -/** Returns true iff \a item is suitable to be included in the selection, in particular - whether it has a bounding box in the desktop coordinate system for rendering resize handles. - - Descendents of nodes (markers etc.) return false, for example. -*/ -bool in_dt_coordsys(SPObject const &item) -{ - /* Definition based on sp_item_i2doc_affine. */ - SPObject const *child = &item; - g_return_val_if_fail(child != NULL, false); - for(;;) { - if (!SP_IS_ITEM(child)) { - return false; - } - SPObject const * const parent = SP_OBJECT_PARENT(child); - if (parent == NULL) { - break; - } - child = parent; - } - g_assert(SP_IS_ROOT(child)); - /* Relevance: Otherwise, I'm not sure whether to return true or false. */ - return true; -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/in-dt-coordsys.h b/src/dialogs/in-dt-coordsys.h deleted file mode 100644 index c2ec96d8e..000000000 --- a/src/dialogs/in-dt-coordsys.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SEEN_IN_DT_COORDSYS -#define SEEN_IN_DT_COORDSYS -#include "forward.h" - -bool in_dt_coordsys(SPObject const &item); - -#endif /* !SEEN_IN_DT_COORDSYS */ - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/item-properties.cpp b/src/dialogs/item-properties.cpp index 076358082..44a479b6c 100644 --- a/src/dialogs/item-properties.cpp +++ b/src/dialogs/item-properties.cpp @@ -26,21 +26,20 @@ #include #include +#include "../desktop-handles.h" +#include "dialog-events.h" +#include "../document.h" #include -#include "helper/window.h" -#include "../widgets/sp-widget.h" +#include "../helper/window.h" #include "../inkscape.h" -#include "../document.h" -#include "../desktop-handles.h" +#include "../interface.h" +#include "../macros.h" +#include "../preferences.h" #include "../selection.h" #include "../sp-item.h" -#include "../macros.h" #include "../verbs.h" -#include "../interface.h" -#include "sp-attribute-widget.h" - -#include "dialog-events.h" -#include "../preferences.h" +#include "../widgets/sp-attribute-widget.h" +#include "../widgets/sp-widget.h" #define MIN_ONSCREEN_DISTANCE 50 diff --git a/src/dialogs/layer-properties.cpp b/src/dialogs/layer-properties.cpp deleted file mode 100644 index ccd91fa2e..000000000 --- a/src/dialogs/layer-properties.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/** @file - * @brief Dialog for renaming layers - */ -/* Author: - * Bryce W. Harrington - * Andrius R. - * - * Copyright (C) 2004 Bryce Harrington - * Copyright (C) 2006 Andrius R. - * - * Released under GNU GPL. Read the file 'COPYING' for more information - */ - -#include -#include -#include "inkscape.h" -#include "desktop.h" -#include "document.h" -#include "layer-manager.h" -#include "message-stack.h" -#include "desktop-handles.h" -#include "sp-object.h" -#include "sp-item.h" - -#include "layer-properties.h" - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -LayerPropertiesDialog::LayerPropertiesDialog() -: _strategy(NULL), _desktop(NULL), _layer(NULL), _position_visible(false) -{ - Gtk::VBox *mainVBox = get_vbox(); - - _layout_table.set_spacings(4); - _layout_table.resize (1, 2); - - // Layer name widgets - _layer_name_entry.set_activates_default(true); - _layer_name_label.set_label(_("Layer name:")); - _layer_name_label.set_alignment(1.0, 0.5); - - _layout_table.attach(_layer_name_label, - 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); - _layout_table.attach(_layer_name_entry, - 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); - mainVBox->pack_start(_layout_table, false, false, 4); - - // Buttons - _close_button.set_use_stock(true); - _close_button.set_label(Gtk::Stock::CANCEL.id); - _close_button.set_flags(Gtk::CAN_DEFAULT); - - _apply_button.set_use_underline(true); - _apply_button.set_flags(Gtk::CAN_DEFAULT); - - _close_button.signal_clicked() - .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)); - _apply_button.signal_clicked() - .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_apply)); - - signal_delete_event().connect( - sigc::bind_return( - sigc::hide(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)), - true - ) - ); - - add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); - add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); - - _apply_button.grab_default(); - - show_all_children(); -} - -LayerPropertiesDialog::~LayerPropertiesDialog() { - _setDesktop(NULL); - _setLayer(NULL); -} - -void LayerPropertiesDialog::_showDialog(LayerPropertiesDialog::Strategy &strategy, - SPDesktop *desktop, SPObject *layer) -{ - LayerPropertiesDialog *dialog = new LayerPropertiesDialog(); - - dialog->_strategy = &strategy; - dialog->_setDesktop(desktop); - dialog->_setLayer(layer); - - dialog->_strategy->setup(*dialog); - - dialog->set_modal(true); - desktop->setWindowTransient (dialog->gobj()); - dialog->property_destroy_with_parent() = true; - - dialog->show(); - dialog->present(); -} - -void -LayerPropertiesDialog::_apply() -{ - g_assert(_strategy != NULL); - - _strategy->perform(*this); - sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_NONE, - _("Add layer")); - - _close(); -} - -void -LayerPropertiesDialog::_close() -{ - _setLayer(NULL); - _setDesktop(NULL); - destroy_(); - Glib::signal_idle().connect( - sigc::bind_return( - sigc::bind(sigc::ptr_fun(&::operator delete), this), - false - ) - ); -} - -void -LayerPropertiesDialog::_setup_position_controls() { - if ( NULL == _layer || _desktop->currentRoot() == _layer ) { - // no layers yet, so option above/below/sublayer is useless - return; - } - - _position_visible = true; - _dropdown_list = Gtk::ListStore::create(_dropdown_columns); - _layer_position_combo.set_model(_dropdown_list); - _layer_position_combo.pack_start(_label_renderer); - _layer_position_combo.set_cell_data_func(_label_renderer, - sigc::mem_fun(*this, &LayerPropertiesDialog::_prepareLabelRenderer)); - - _layout_table.resize (2, 2); - - Gtk::ListStore::iterator row; - row = _dropdown_list->append(); - row->set_value(_dropdown_columns.position, LPOS_ABOVE); - row->set_value(_dropdown_columns.name, Glib::ustring(_("Above current"))); - _layer_position_combo.set_active(row); - row = _dropdown_list->append(); - row->set_value(_dropdown_columns.position, LPOS_BELOW); - row->set_value(_dropdown_columns.name, Glib::ustring(_("Below current"))); - row = _dropdown_list->append(); - row->set_value(_dropdown_columns.position, LPOS_CHILD); - row->set_value(_dropdown_columns.name, Glib::ustring(_("As sublayer of current"))); - - _layout_table.attach(_layer_position_combo, - 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); - _layer_position_label.set_label(_("Position:")); - _layer_position_label.set_alignment(1.0, 0.5); - _layout_table.attach(_layer_position_label, - 0, 1, 1, 2, Gtk::FILL, Gtk::FILL); - show_all_children(); -} - -/** Formats the label for a given layer row - */ -void LayerPropertiesDialog::_prepareLabelRenderer( - Gtk::TreeModel::const_iterator const &row -) { - Glib::ustring name=(*row)[_dropdown_columns.name]; - _label_renderer.property_markup() = name.c_str(); -} - -void LayerPropertiesDialog::Rename::setup(LayerPropertiesDialog &dialog) { - SPDesktop *desktop=dialog._desktop; - dialog.set_title(_("Rename Layer")); - gchar const *name = desktop->currentLayer()->label(); - dialog._layer_name_entry.set_text(( name ? name : "" )); - dialog._apply_button.set_label(_("_Rename")); -} - -void LayerPropertiesDialog::Rename::perform(LayerPropertiesDialog &dialog) { - SPDesktop *desktop=dialog._desktop; - Glib::ustring name(dialog._layer_name_entry.get_text()); - desktop->layer_manager->renameLayer( desktop->currentLayer(), - ( name.empty() ? NULL : (gchar *)name.c_str() ) - ); - sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, - _("Rename layer")); - // TRANSLATORS: This means "The layer has been renamed" - desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Renamed layer")); -} - -void LayerPropertiesDialog::Create::setup(LayerPropertiesDialog &dialog) { - dialog.set_title(_("Add Layer")); - dialog._layer_name_entry.set_text(""); - dialog._apply_button.set_label(_("_Add")); - dialog._setup_position_controls(); -} - -void LayerPropertiesDialog::Create::perform(LayerPropertiesDialog &dialog) { - SPDesktop *desktop=dialog._desktop; - - LayerRelativePosition position = LPOS_ABOVE; - - if (dialog._position_visible) { - Gtk::ListStore::iterator activeRow(dialog._layer_position_combo.get_active()); - position = activeRow->get_value(dialog._dropdown_columns.position); - } - - SPObject *new_layer=Inkscape::create_layer(desktop->currentRoot(), dialog._layer, position); - - Glib::ustring name(dialog._layer_name_entry.get_text()); - if (!name.empty()) { - desktop->layer_manager->renameLayer( new_layer, (gchar *)name.c_str() ); - } - sp_desktop_selection(desktop)->clear(); - desktop->setCurrentLayer(new_layer); - desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("New layer created.")); -} - -void LayerPropertiesDialog::_setDesktop(SPDesktop *desktop) { - if (desktop) { - Inkscape::GC::anchor (desktop); - } - if (_desktop) { - Inkscape::GC::release (_desktop); - } - _desktop = desktop; -} - -void LayerPropertiesDialog::_setLayer(SPObject *layer) { - if (layer) { - sp_object_ref(layer, NULL); - } - if (_layer) { - sp_object_unref(_layer, NULL); - } - _layer = layer; -} - -} // namespace -} // namespace -} // namespace - - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/layer-properties.h b/src/dialogs/layer-properties.h deleted file mode 100644 index 807967e8d..000000000 --- a/src/dialogs/layer-properties.h +++ /dev/null @@ -1,132 +0,0 @@ -/** @file - * @brief Dialog for renaming layers - */ -/* Author: - * Bryce W. Harrington - * - * Copyright (C) 2004 Bryce Harrington - * - * Released under GNU GPL. Read the file 'COPYING' for more information - */ - -#ifndef INKSCAPE_DIALOG_LAYER_PROPERTIES_H -#define INKSCAPE_DIALOG_LAYER_PROPERTIES_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "selection.h" -#include "layer-fns.h" - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -class LayerPropertiesDialog : public Gtk::Dialog { - public: - LayerPropertiesDialog(); - virtual ~LayerPropertiesDialog(); - - Glib::ustring getName() const { return "LayerPropertiesDialog"; } - - static void showRename(SPDesktop *desktop, SPObject *layer) { - _showDialog(Rename::instance(), desktop, layer); - } - static void showCreate(SPDesktop *desktop, SPObject *layer) { - _showDialog(Create::instance(), desktop, layer); - } - -protected: - struct Strategy { - virtual ~Strategy() {} - virtual void setup(LayerPropertiesDialog &)=0; - virtual void perform(LayerPropertiesDialog &)=0; - }; - struct Rename : public Strategy { - static Rename &instance() { static Rename instance; return instance; } - void setup(LayerPropertiesDialog &dialog); - void perform(LayerPropertiesDialog &dialog); - }; - struct Create : public Strategy { - static Create &instance() { static Create instance; return instance; } - void setup(LayerPropertiesDialog &dialog); - void perform(LayerPropertiesDialog &dialog); - }; - - friend class Rename; - friend class Create; - - Strategy *_strategy; - SPDesktop *_desktop; - SPObject *_layer; - - class PositionDropdownColumns : public Gtk::TreeModel::ColumnRecord { - public: - Gtk::TreeModelColumn position; - Gtk::TreeModelColumn name; - - PositionDropdownColumns() { - add(position); add(name); - } - }; - - Gtk::Label _layer_name_label; - Gtk::Entry _layer_name_entry; - Gtk::Label _layer_position_label; - Gtk::ComboBox _layer_position_combo; - Gtk::Table _layout_table; - bool _position_visible; - - PositionDropdownColumns _dropdown_columns; - Gtk::CellRendererText _label_renderer; - Glib::RefPtr _dropdown_list; - - Gtk::Button _close_button; - Gtk::Button _apply_button; - - sigc::connection _destroy_connection; - - static LayerPropertiesDialog &_instance() { - static LayerPropertiesDialog instance; - return instance; - } - - void _setDesktop(SPDesktop *desktop); - void _setLayer(SPObject *layer); - - static void _showDialog(Strategy &strategy, SPDesktop *desktop, SPObject *layer); - void _apply(); - void _close(); - - void _setup_position_controls(); - void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); - -private: - LayerPropertiesDialog(LayerPropertiesDialog const &); // no copy - LayerPropertiesDialog &operator=(LayerPropertiesDialog const &); // no assign -}; - -} // namespace -} // namespace -} // namespace - - -#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/layers-panel.cpp b/src/dialogs/layers-panel.cpp deleted file mode 100644 index c826777a2..000000000 --- a/src/dialogs/layers-panel.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/* - * A simple panel for layers - * - * Authors: - * Jon A. Cruz - * - * Copyright (C) 2006 Jon A. Cruz - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include -#include - -#include - -#include "inkscape.h" - -#include "layers-panel.h" - -#include "layer-manager.h" -#include "layer-fns.h" - -#include "verbs.h" -#include "helper/action.h" - -#include "document.h" -#include "desktop.h" -#include "sp-object.h" -#include "sp-item.h" -#include "widgets/icon.h" -#include "ui/widget/imagetoggler.h" -#include -#include "preferences.h" -#include "xml/repr.h" -#include "svg/css-ostringstream.h" -#include "desktop-style.h" -#include "ui/icon-names.h" - -//#define DUMP_LAYERS 1 - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -LayersPanel& -LayersPanel::getInstance() -{ - return *new LayersPanel(); -} - -enum { - COL_VISIBLE = 1, - COL_LOCKED -}; - -enum { - BUTTON_NEW = 0, - BUTTON_RENAME, - BUTTON_TOP, - BUTTON_BOTTOM, - BUTTON_UP, - BUTTON_DOWN, - BUTTON_DUPLICATE, - BUTTON_DELETE, - BUTTON_SOLO -}; - -class LayersPanel::InternalUIBounce -{ -public: - int _actionCode; - SPObject* _target; -}; - -static gboolean layers_panel_activated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) -{ - if ( data ) - { - LayersPanel* panel = reinterpret_cast(data); - panel->setDesktop(panel->getDesktop()); - } - - return FALSE; -} - -static gboolean layers_panel_deactivated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) -{ - if ( data ) - { - LayersPanel* panel = reinterpret_cast(data); - panel->setDesktop(NULL); - } - - return FALSE; -} - - -void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ) -{ - bool set = false; - - if ( iconName ) { - GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName ); - gtk_widget_show( child ); - btn.add( *manage(Glib::wrap(child)) ); - set = true; - } - - if ( desktop ) { - Verb *verb = Verb::get( code ); - if ( verb ) { - SPAction *action = verb->get_action(desktop); - if ( !set && action && action->image ) { - GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image ); - gtk_widget_show( child ); - btn.add( *manage(Glib::wrap(child)) ); - set = true; - } - - if ( action && action->tip ) { - _tips.set_tip( btn, action->tip ); - } - } - } - - if ( !set && fallback ) { - btn.set_label( fallback ); - } -} - - -Gtk::MenuItem& LayersPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ) -{ - GtkWidget* iconWidget = 0; - const char* label = 0; - - if ( iconName ) { - iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName ); - } - - if ( desktop ) { - Verb *verb = Verb::get( code ); - if ( verb ) { - SPAction *action = verb->get_action(desktop); - if ( !iconWidget && action && action->image ) { - iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image ); - } - - if ( action ) { - label = action->name; - } - } - } - - if ( !label && fallback ) { - label = fallback; - } - - Gtk::Widget* wrapped = 0; - if ( iconWidget ) { - wrapped = manage(Glib::wrap(iconWidget)); - wrapped->show(); - } - - - - Gtk::Menu::MenuList& menulist = _popupMenu.items(); - - if ( wrapped ) { - menulist.push_back( Gtk::Menu_Helpers::ImageMenuElem( label, *wrapped, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); - } else { - menulist.push_back( Gtk::Menu_Helpers::MenuElem( label, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); - } - return menulist.back(); -} - -void LayersPanel::_fireAction( unsigned int code ) -{ - if ( _desktop ) { - Verb *verb = Verb::get( code ); - if ( verb ) { - SPAction *action = verb->get_action(_desktop); - if ( action ) { - sp_action_perform( action, NULL ); -// } else { -// g_message("no action"); - } -// } else { -// g_message("no verb for %u", code); - } -// } else { -// g_message("no active desktop"); - } -} - -// SP_VERB_LAYER_NEXT, -// SP_VERB_LAYER_PREV, -void LayersPanel::_takeAction( int val ) -{ - if ( !_pending ) { - _pending = new InternalUIBounce(); - _pending->_actionCode = val; - _pending->_target = _selectedLayer(); - Glib::signal_timeout().connect( sigc::mem_fun(*this, &LayersPanel::_executeAction), 0 ); - } -} - -bool LayersPanel::_executeAction() -{ - // Make sure selected layer hasn't changed since the action was triggered - if ( _pending - && ( - (_pending->_actionCode == BUTTON_NEW) - || !( (_desktop && _desktop->currentLayer()) - && (_desktop->currentLayer() != _pending->_target) - ) - ) - ) { - int val = _pending->_actionCode; -// SPObject* target = _pending->_target; - - switch ( val ) { - case BUTTON_NEW: - { - _fireAction( SP_VERB_LAYER_NEW ); - } - break; - case BUTTON_RENAME: - { - _fireAction( SP_VERB_LAYER_RENAME ); - } - break; - case BUTTON_TOP: - { - _fireAction( SP_VERB_LAYER_TO_TOP ); - } - break; - case BUTTON_BOTTOM: - { - _fireAction( SP_VERB_LAYER_TO_BOTTOM ); - } - break; - case BUTTON_UP: - { - _fireAction( SP_VERB_LAYER_RAISE ); - } - break; - case BUTTON_DOWN: - { - _fireAction( SP_VERB_LAYER_LOWER ); - } - break; - case BUTTON_DUPLICATE: - { - _fireAction( SP_VERB_LAYER_DUPLICATE ); - } - break; - case BUTTON_DELETE: - { - _fireAction( SP_VERB_LAYER_DELETE ); - } - case BUTTON_SOLO: - { - _fireAction( SP_VERB_LAYER_SOLO ); - } - break; - } - - delete _pending; - _pending = 0; - } - - return false; -} - -class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord -{ -public: - - ModelColumns() - { - add(_colObject); - add(_colVisible); - add(_colLocked); - add(_colLabel); - } - virtual ~ModelColumns() {} - - Gtk::TreeModelColumn _colObject; - Gtk::TreeModelColumn _colLabel; - Gtk::TreeModelColumn _colVisible; - Gtk::TreeModelColumn _colLocked; -}; - -void LayersPanel::_updateLayer( SPObject *layer ) { - _store->foreach( sigc::bind(sigc::mem_fun(*this, &LayersPanel::_checkForUpdated), layer) ); -} - -bool LayersPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* layer) -{ - bool stopGoing = false; - Gtk::TreeModel::Row row = *iter; - Glib::ustring tmp = row[_model->_colLabel]; - if ( layer == row[_model->_colObject] ) - { - row[_model->_colLabel] = layer->label() ? layer->label() : SP_OBJECT_ID(layer); - row[_model->_colVisible] = SP_IS_ITEM(layer) ? !SP_ITEM(layer)->isHidden() : false; - row[_model->_colLocked] = SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false; - - stopGoing = true; - } - - return stopGoing; -} - -void LayersPanel::_selectLayer( SPObject *layer ) { - if ( !layer || (_desktop && _desktop->doc() && (layer == _desktop->doc()->root)) ) { - if ( _tree.get_selection()->count_selected_rows() != 0 ) { - _tree.get_selection()->unselect_all(); - } - } else { - _store->foreach( sigc::bind(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) ); - } - - _checkTreeSelection(); -} - -bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer) -{ - bool stopGoing = false; - - Gtk::TreeModel::Row row = *iter; - if ( layer == row[_model->_colObject] ) - { - _tree.expand_to_path( path ); - - Glib::RefPtr select = _tree.get_selection(); - - select->select(iter); - - stopGoing = true; - } - - return stopGoing; -} - -void LayersPanel::_layersChanged() -{ -// g_message("_layersChanged()"); - SPDocument* document = _desktop->doc(); - SPObject* root = document->root; - if ( root ) { - _selectedConnection.block(); - if ( _mgr && _mgr->includes( root ) ) { - SPObject* target = _desktop->currentLayer(); - _store->clear(); - -#if DUMP_LAYERS - g_message("root:%p {%s} [%s]", root, root->id, root->label() ); -#endif // DUMP_LAYERS - _addLayer( document, root, 0, target, 0 ); - } - _selectedConnection.unblock(); - } -} - -void LayersPanel::_addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ) -{ - if ( layer && (level < _maxNestDepth) ) { - unsigned int counter = _mgr->childCount(layer); - for ( unsigned int i = 0; i < counter; i++ ) { - SPObject *child = _mgr->nthChildOf(layer, i); - if ( child ) { -#if DUMP_LAYERS - g_message(" %3d layer:%p {%s} [%s]", level, child, child->id, child->label() ); -#endif // DUMP_LAYERS - - Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend(); - Gtk::TreeModel::Row row = *iter; - row[_model->_colObject] = child; - row[_model->_colLabel] = child->label() ? child->label() : SP_OBJECT_ID(child); - row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false; - row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false; - - if ( target && child == target ) { - _tree.expand_to_path( _store->get_path(iter) ); - - Glib::RefPtr select = _tree.get_selection(); - select->select(iter); - - _checkTreeSelection(); - } - - _addLayer( doc, child, &row, target, level + 1 ); - } - } - } -} - -SPObject* LayersPanel::_selectedLayer() -{ - SPObject* obj = 0; - - Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); - if ( iter ) { - Gtk::TreeModel::Row row = *iter; - obj = row[_model->_colObject]; - } - - return obj; -} - -void LayersPanel::_pushTreeSelectionToCurrent() -{ - SPObject* inTree = _selectedLayer(); - // TODO hunt down the possible API abuse in getting NULL - if ( _desktop->currentRoot() ) { - if ( inTree ) { - SPObject* curr = _desktop->currentLayer(); - if ( curr != inTree ) { - _mgr->setCurrentLayer( inTree ); - } - } else { - _mgr->setCurrentLayer( _desktop->doc()->root ); - } - } -} - -void LayersPanel::_checkTreeSelection() -{ - bool sensitive = false; - bool sensitiveNonTop = false; - bool sensitiveNonBottom = false; - if ( _tree.get_selection()->count_selected_rows() > 0 ) { - sensitive = true; - - SPObject* inTree = _selectedLayer(); - if ( inTree ) { - - sensitiveNonTop = (Inkscape::next_layer(inTree->parent, inTree) != 0); - sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0); - - } - } - - - for ( std::vector::iterator it = _watching.begin(); it != _watching.end(); ++it ) { - (*it)->set_sensitive( sensitive ); - } - for ( std::vector::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { - (*it)->set_sensitive( sensitiveNonTop ); - } - for ( std::vector::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { - (*it)->set_sensitive( sensitiveNonBottom ); - } -} - -void LayersPanel::_preToggle( GdkEvent const *event ) -{ - if ( _toggleEvent ) { - gdk_event_free(_toggleEvent); - _toggleEvent = 0; - } - - if ( event && (event->type == GDK_BUTTON_PRESS) ) { - // Make a copy so we can keep it around. - _toggleEvent = gdk_event_copy(const_cast(event)); - } -} - -void LayersPanel::_toggled( Glib::ustring const& str, int targetCol ) -{ - Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str); - Gtk::TreeModel::Row row = *iter; - - Glib::ustring tmp = row[_model->_colLabel]; - - SPObject* obj = row[_model->_colObject]; - SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0; - if ( item ) { - switch ( targetCol ) { - case COL_VISIBLE: - { - bool newValue = !row[_model->_colVisible]; - row[_model->_colVisible] = newValue; - item->setHidden( !newValue ); - item->updateRepr(); - sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, - newValue? _("Unhide layer") : _("Hide layer")); - } - break; - - case COL_LOCKED: - { - bool newValue = !row[_model->_colLocked]; - row[_model->_colLocked] = newValue; - item->setLocked( newValue ); - item->updateRepr(); - sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, - newValue? _("Lock layer") : _("Unlock layer")); - } - break; - } - } -} - -void LayersPanel::_handleButtonEvent(GdkEventButton* evt) -{ - // TODO - fix to a better is-popup function - if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) { - - - { - Gtk::TreeModel::Path path; - Gtk::TreeViewColumn* col = 0; - int x = static_cast(evt->x); - int y = static_cast(evt->y); - int x2 = 0; - int y2 = 0; - if ( _tree.get_path_at_pos( x, y, - path, col, - x2, y2 ) ) { - _checkTreeSelection(); - _popupMenu.popup(evt->button, evt->time); - } - } - - } -} - -void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter ) -{ - Gtk::TreeModel::Row row = *iter; - if ( row ) { - SPObject* obj = row[_model->_colObject]; - if ( obj ) { - gchar const* oldLabel = obj->label(); - Glib::ustring tmp = row[_model->_colLabel]; - if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) { - _mgr->renameLayer( obj, tmp.c_str() ); - row[_model->_colLabel] = obj->label(); - } - } - } -} - -bool LayersPanel::_rowSelectFunction( Glib::RefPtr const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected ) -{ - bool val = true; - if ( !currentlySelected && _toggleEvent ) - { - GdkEvent* event = gtk_get_current_event(); - if ( event ) { - // (keep these checks separate, so we know when to call gdk_event_free() - if ( event->type == GDK_BUTTON_PRESS ) { - GdkEventButton const* target = reinterpret_cast(_toggleEvent); - GdkEventButton const* evtb = reinterpret_cast(event); - - if ( (evtb->window == target->window) - && (evtb->send_event == target->send_event) - && (evtb->time == target->time) - && (evtb->state == target->state) - ) - { - // Ooooh! It's a magic one - val = false; - } - } - gdk_event_free(event); - } - } - return val; -} - -/** - * Constructor - */ -LayersPanel::LayersPanel() : - UI::Widget::Panel("", "/dialogs/layers", SP_VERB_DIALOG_LAYERS), - _maxNestDepth(20), - _mgr(0), - _desktop(0), - _model(0), - _pending(0), - _toggleEvent(0), - _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", UI::Widget::SimpleFilterModifier::BLEND) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - _maxNestDepth = prefs->getIntLimited("/dialogs/layers/maxDepth", 20, 1, 1000); - - ModelColumns *zoop = new ModelColumns(); - _model = zoop; - - _store = Gtk::TreeStore::create( *zoop ); - - _tree.set_model( _store ); - _tree.set_headers_visible(false); - - Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler( - INKSCAPE_ICON_OBJECT_VISIBLE, INKSCAPE_ICON_OBJECT_HIDDEN) ); - int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1; - eyeRenderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); - eyeRenderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) ); - eyeRenderer->property_activatable() = true; - Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum); - if ( col ) { - col->add_attribute( eyeRenderer->property_active(), _model->_colVisible ); - } - - Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler( - INKSCAPE_ICON_OBJECT_LOCKED, INKSCAPE_ICON_OBJECT_UNLOCKED) ); - int lockedColNum = _tree.append_column("lock", *renderer) - 1; - renderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); - renderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) ); - renderer->property_activatable() = true; - col = _tree.get_column(lockedColNum); - if ( col ) { - col->add_attribute( renderer->property_active(), _model->_colLocked ); - } - - int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1; - - _tree.set_expander_column( *_tree.get_column(nameColNum) ); - - _compositeSettings.setSubject(&_subject); - - _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) ); - _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) ); - - _tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) ); - _tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) ); - - _scroller.add( _tree ); - _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); - _scroller.set_shadow_type(Gtk::SHADOW_IN); - - _watching.push_back( &_compositeSettings ); - - _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET ); - _layersPage.pack_end(_compositeSettings, Gtk::PACK_SHRINK); - _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK); - - _notebook.append_page(_layersPage, _("Layers")); - - _getContents()->pack_start(_notebook, Gtk::PACK_EXPAND_WIDGET); - - SPDesktop* targetDesktop = getDesktop(); - - _buttonsRow.set_child_min_width( 16 ); - - Gtk::Button* btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("New") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) ); - _buttonsRow.add( *btn ); - - btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, _("Top") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) ); - _watchingNonTop.push_back( btn ); - _buttonsRow.add( *btn ); - - btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, _("Up") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) ); - _watchingNonTop.push_back( btn ); - _buttonsRow.add( *btn ); - - btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, _("Dn") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) ); - _watchingNonBottom.push_back( btn ); - _buttonsRow.add( *btn ); - - btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, _("Bot") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) ); - _watchingNonBottom.push_back( btn ); - _buttonsRow.add( *btn ); - -// btn = manage( new Gtk::Button("Dup") ); -// btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) ); -// _buttonsRow.add( *btn ); - - btn = manage( new Gtk::Button() ); - _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("X") ); - btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) ); - _watching.push_back( btn ); - _buttonsRow.add( *btn ); - - - - - // ------------------------------------------------------- - { - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) ); - - _popupMenu.items().push_back( Gtk::Menu_Helpers::SeparatorElem() ); - - _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) ); - _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) ); - - _popupMenu.show_all_children(); - } - // ------------------------------------------------------- - - - - for ( std::vector::iterator it = _watching.begin(); it != _watching.end(); ++it ) { - (*it)->set_sensitive( false ); - } - for ( std::vector::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { - (*it)->set_sensitive( false ); - } - for ( std::vector::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { - (*it)->set_sensitive( false ); - } - - g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this ); - g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", G_CALLBACK( layers_panel_deactivated ), this ); - setDesktop( targetDesktop ); - - show_all_children(); - - // restorePanelPrefs(); -} - -LayersPanel::~LayersPanel() -{ - setDesktop(NULL); - - _compositeSettings.setSubject(NULL); - - if ( _model ) - { - delete _model; - } - - if ( _toggleEvent ) - { - gdk_event_free( _toggleEvent ); - _toggleEvent = 0; - } -} - - -void LayersPanel::setDesktop( SPDesktop* desktop ) -{ - Panel::setDesktop(desktop); - - if ( desktop != _desktop ) { - _layerChangedConnection.disconnect(); - _layerUpdatedConnection.disconnect(); - _changedConnection.disconnect(); - if ( _mgr ) { - _mgr = 0; - } - if ( _desktop ) { - _desktop = 0; - } - - _desktop = getDesktop(); - if ( _desktop ) { - //setLabel( _desktop->doc()->name ); - - _mgr = _desktop->layer_manager; - if ( _mgr ) { - _layerChangedConnection = _mgr->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) ); - _layerUpdatedConnection = _mgr->connectLayerDetailsChanged( sigc::mem_fun(*this, &LayersPanel::_updateLayer) ); - _changedConnection = _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) ); - } - - _layersChanged(); - } - } -/* - GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" ); - g_message( "layers list starts at %p", layers ); - for ( GSList const *iter=layers ; iter ; iter = iter->next ) { - SPObject *layer=static_cast(iter->data); - g_message(" {%s} [%s]", layer->id, layer->label() ); - } -*/ -} - - - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/layers-panel.h b/src/dialogs/layers-panel.h deleted file mode 100644 index 1f593b9c6..000000000 --- a/src/dialogs/layers-panel.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * A simple dialog for layer UI. - * - * Authors: - * Jon A. Cruz - * - * Copyright (C) 2006 Jon A. Cruz - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_LAYERS_PANEL_H -#define SEEN_LAYERS_PANEL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#include "ui/previewholder.h" -#include "ui/widget/panel.h" -#include "ui/widget/object-composite-settings.h" - -class SPObject; - -namespace Inkscape { - -class LayerManager; - -namespace UI { -namespace Dialogs { - - -/** - * A panel that displays layers. - */ -class LayersPanel : public UI::Widget::Panel -{ -public: - LayersPanel(); - virtual ~LayersPanel(); - - //virtual void setOrientation( Gtk::AnchorType how ); - - static LayersPanel& getInstance(); - - void setDesktop( SPDesktop* desktop ); - -protected: - //virtual void _handleAction( int setId, int itemId ); - -private: - class ModelColumns; - class InternalUIBounce; - - LayersPanel(LayersPanel const &); // no copy - LayersPanel &operator=(LayersPanel const &); // no assign - - void _styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ); - void _fireAction( unsigned int code ); - Gtk::MenuItem& _addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ); - - void _preToggle( GdkEvent const *event ); - void _toggled( Glib::ustring const& str, int targetCol ); - - void _handleButtonEvent(GdkEventButton* evt); - void _handleRowChange( Gtk::TreeModel::Path const& path, Gtk::TreeModel::iterator const& iter ); - - void _pushTreeSelectionToCurrent(); - void _checkTreeSelection(); - - void _takeAction( int val ); - bool _executeAction(); - - bool _rowSelectFunction( Glib::RefPtr const & model, Gtk::TreeModel::Path const & path, bool b ); - - void _updateLayer(SPObject *layer); - bool _checkForUpdated(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer); - - void _selectLayer(SPObject *layer); - bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPObject* layer); - - void _layersChanged(); - void _addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ); - - SPObject* _selectedLayer(); - - // Hooked to the layer manager: - sigc::connection _layerChangedConnection; - sigc::connection _layerUpdatedConnection; - sigc::connection _changedConnection; - sigc::connection _addedConnection; - sigc::connection _removedConnection; - - // Internal - sigc::connection _selectedConnection; - - int _maxNestDepth; - Inkscape::LayerManager* _mgr; - SPDesktop* _desktop; - ModelColumns* _model; - InternalUIBounce* _pending; - GdkEvent* _toggleEvent; - Glib::RefPtr _store; - std::vector _watching; - std::vector _watchingNonTop; - std::vector _watchingNonBottom; - - Gtk::Tooltips _tips; - Gtk::TreeView _tree; - Gtk::HButtonBox _buttonsRow; - Gtk::ScrolledWindow _scroller; - Gtk::Menu _popupMenu; - Gtk::SpinButton _spinBtn; - Gtk::Notebook _notebook; - Gtk::VBox _layersPage; - - UI::Widget::StyleSubject::CurrentLayer _subject; - UI::Widget::ObjectCompositeSettings _compositeSettings; -}; - - - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - - -#endif // SEEN_LAYERS_PANEL_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/object-attributes.cpp b/src/dialogs/object-attributes.cpp index d9bcf1489..320840f76 100644 --- a/src/dialogs/object-attributes.cpp +++ b/src/dialogs/object-attributes.cpp @@ -13,17 +13,16 @@ #include #include #include +#include +#include +#include #include "helper/window.h" #include "macros.h" #include "sp-anchor.h" -#include "sp-attribute-widget.h" +#include "widgets/sp-attribute-widget.h" #include "../xml/repr.h" -#include -#include -#include - struct SPAttrDesc { gchar const *label; gchar const *attribute; diff --git a/src/dialogs/rdf.cpp b/src/dialogs/rdf.cpp deleted file mode 100644 index f0b174922..000000000 --- a/src/dialogs/rdf.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -/** @file - * @brief RDF manipulation functions - * - * @todo move these to xml/ instead of dialogs/ - */ -/* Authors: - * Kees Cook - * Jon Phillips - * - * Copyright (C) 2004 Kees Cook - * Copyright (C) 2006 Jon Phillips - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "xml/repr.h" -#include "rdf.h" -#include "sp-item-group.h" -#include "inkscape.h" - -/* - Example RDF XML from various places... - - - - title of work - year - description of work - - creator - - - holder - - - - - - - - - - SVG Road Signs - - John Cliff - - - - - - - - - - - - - - -Bag example: - - - -open clip art logo -images -logo -clip art -ocal -logotype -filetype - - -*/ - -struct rdf_double_t rdf_license_empty [] = { - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a_sa [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a_nd [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a_nc [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a_nc_sa [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_cc_a_nc_nd [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_pd [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_freeart [] = { - { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, - { "cc:permits", "http://creativecommons.org/ns#Distribution", }, - { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, - { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, - { "cc:requires", "http://creativecommons.org/ns#Notice", }, - { "cc:requires", "http://creativecommons.org/ns#Attribution", }, - { NULL, NULL } -}; - -struct rdf_double_t rdf_license_ofl [] = { - { "cc:permits", "http://scripts.sil.org/pub/OFL/Reproduction", }, - { "cc:permits", "http://scripts.sil.org/pub/OFL/Distribution", }, - { "cc:permits", "http://scripts.sil.org/pub/OFL/Embedding", }, - { "cc:permits", "http://scripts.sil.org/pub/OFL/DerivativeWorks", }, - { "cc:requires", "http://scripts.sil.org/pub/OFL/Notice", }, - { "cc:requires", "http://scripts.sil.org/pub/OFL/Attribution", }, - { "cc:requires", "http://scripts.sil.org/pub/OFL/ShareAlike", }, - { "cc:requires", "http://scripts.sil.org/pub/OFL/DerivativeRenaming", }, - { "cc:requires", "http://scripts.sil.org/pub/OFL/BundlingWhenSelling", }, - { NULL, NULL } -}; - -struct rdf_license_t rdf_licenses [] = { - { N_("CC Attribution"), - "http://creativecommons.org/licenses/by/3.0/", - rdf_license_cc_a, - }, - - { N_("CC Attribution-ShareAlike"), - "http://creativecommons.org/licenses/by-sa/3.0/", - rdf_license_cc_a_sa, - }, - - { N_("CC Attribution-NoDerivs"), - "http://creativecommons.org/licenses/by-nd/3.0/", - rdf_license_cc_a_nd, - }, - - { N_("CC Attribution-NonCommercial"), - "http://creativecommons.org/licenses/by-nc/3.0/", - rdf_license_cc_a_nc, - }, - - { N_("CC Attribution-NonCommercial-ShareAlike"), - "http://creativecommons.org/licenses/by-nc-sa/3.0/", - rdf_license_cc_a_nc_sa, - }, - - { N_("CC Attribution-NonCommercial-NoDerivs"), - "http://creativecommons.org/licenses/by-nc-nd/3.0/", - rdf_license_cc_a_nc_nd, - }, - - { N_("Public Domain"), - "http://creativecommons.org/licenses/publicdomain/", - rdf_license_pd, - }, - - { N_("FreeArt"), - "http://artlibre.org/licence.php/lalgb.html", - rdf_license_freeart, - }, - - { N_("Open Font License"), - "http://scripts.sil.org/OFL", - rdf_license_ofl, - }, - - { NULL, NULL, rdf_license_empty, } -}; - -#define XML_TAG_NAME_SVG "svg:svg" -#define XML_TAG_NAME_METADATA "svg:metadata" -#define XML_TAG_NAME_RDF "rdf:RDF" -#define XML_TAG_NAME_WORK "cc:Work" -#define XML_TAG_NAME_LICENSE "cc:License" - -// Remember when using the "title" and "tip" elements to pass them through -// the localization functions when you use them! -struct rdf_work_entity_t rdf_work_entities [] = { - { "title", N_("Title"), "dc:title", RDF_CONTENT, - N_("Name by which this document is formally known."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "date", N_("Date"), "dc:date", RDF_CONTENT, - N_("Date associated with the creation of this document (YYYY-MM-DD)."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "format", N_("Format"), "dc:format", RDF_CONTENT, - N_("The physical or digital manifestation of this document (MIME type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, - }, - { "type", N_("Type"), "dc:type", RDF_RESOURCE, - N_("Type of document (DCMI Type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, - }, - - { "creator", N_("Creator"), "dc:creator", RDF_AGENT, - N_("Name of entity primarily responsible for making the content of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "rights", N_("Rights"), "dc:rights", RDF_AGENT, - N_("Name of entity with rights to the Intellectual Property of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "publisher", N_("Publisher"), "dc:publisher", RDF_AGENT, - N_("Name of entity responsible for making this document available."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - - { "identifier", N_("Identifier"), "dc:identifier", RDF_CONTENT, - N_("Unique URI to reference this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "source", N_("Source"), "dc:source", RDF_CONTENT, - N_("Unique URI to reference the source of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "relation", N_("Relation"), "dc:relation", RDF_CONTENT, - N_("Unique URI to a related document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "language", N_("Language"), "dc:language", RDF_CONTENT, - N_("Two-letter language tag with optional subtags for the language of this document. (e.g. 'en-GB')"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - { "subject", N_("Keywords"), "dc:subject", RDF_BAG, - N_("The topic of this document as comma-separated key words, phrases, or classifications."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content. - // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/ - { "coverage", N_("Coverage"), "dc:coverage", RDF_CONTENT, - N_("Extent or scope of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, - }, - - { "description", N_("Description"), "dc:description", RDF_CONTENT, - N_("A short account of the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC, - }, - - // FIXME: need to handle 1 agent per line of input - { "contributor", N_("Contributors"), "dc:contributor", RDF_AGENT, - N_("Names of entities responsible for making contributions to the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC, - }, - - // TRANSLATORS: URL to a page that defines the license for the document - { "license_uri", N_("URI"), "cc:license", RDF_RESOURCE, - // TRANSLATORS: this is where you put a URL to a page that defines the license - N_("URI to this document's license's namespace definition."), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL, - }, - - // TRANSLATORS: fragment of XML representing the license of the document - { "license_fragment", N_("Fragment"), "License", RDF_XML, - N_("XML fragment for the RDF 'License' section."), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL, - }, - - { NULL, NULL, NULL, RDF_CONTENT, - NULL, RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, - } -}; - -/** - * \brief Retrieves a known RDF/Work entity by name - * \return A pointer to an RDF/Work entity - * \param name The desired RDF/Work entity - * - */ -struct rdf_work_entity_t * -rdf_find_entity(gchar const * name) -{ - struct rdf_work_entity_t *entity; - for (entity=rdf_work_entities; entity->name; entity++) { - if (strcmp(entity->name,name)==0) break; - } - if (entity->name) return entity; - return NULL; -} - -/* - * Takes the inkscape rdf struct and spits out a static RDF, which is only - * useful for testing. We must merge the rdf struct into the XML DOM for - * changes to be saved. - */ -/* - - Since g_markup_printf_escaped doesn't exist for most people's glib - right now, this function will remain commented out since it's only - for generic debug anyway. --Kees - -gchar * -rdf_string(struct rdf_t * rdf) -{ - gulong overall=0; - gchar *string=NULL; - - gchar *rdf_head="\ -\ -"; - gchar *work_head="\ -\ - \ -"; - gchar *work_title=NULL; - gchar *work_date=NULL; - gchar *work_description=NULL; - gchar *work_creator=NULL; - gchar *work_owner=NULL; - gchar *work_source=NULL; - gchar *work_license=NULL; - gchar *license_head=NULL; - gchar *license=NULL; - gchar *license_end="\n"; - gchar *work_end="\n"; - gchar *rdf_end="\n"; - - if (rdf && rdf->work_title && rdf->work_title[0]) { - work_title=g_markup_printf_escaped(" %s\n", - rdf->work_title); - overall+=strlen(work_title); - } - if (rdf && rdf->work_date && rdf->work_date[0]) { - work_date=g_markup_printf_escaped(" %s\n", - rdf->work_date); - overall+=strlen(work_date); - } - if (rdf && rdf->work_description && rdf->work_description[0]) { - work_description=g_markup_printf_escaped(" %s\n", - rdf->work_description); - overall+=strlen(work_description); - } - if (rdf && rdf->work_creator && rdf->work_creator[0]) { - work_creator=g_markup_printf_escaped(" \ - %s\ - \n", - rdf->work_creator); - overall+=strlen(work_creator); - } - if (rdf && rdf->work_owner && rdf->work_owner[0]) { - work_owner=g_markup_printf_escaped(" \ - %s\ - \n", - rdf->work_owner); - overall+=strlen(work_owner); - } - if (rdf && rdf->work_source && rdf->work_source[0]) { - work_source=g_markup_printf_escaped(" \n", - rdf->work_source); - overall+=strlen(work_source); - } - if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) { - work_license=g_markup_printf_escaped(" \n", - rdf->license->work_rdf); - overall+=strlen(work_license); - - license_head=g_markup_printf_escaped("\n", - rdf->license->work_rdf); - overall+=strlen(license_head); - overall+=strlen(rdf->license->license_rdf); - overall+=strlen(license_end); - } - - overall+=strlen(rdf_head)+strlen(rdf_end); - overall+=strlen(work_head)+strlen(work_end); - - overall++; // NULL term - - if (!(string=(gchar*)g_malloc(overall))) { - return NULL; - } - - string[0]='\0'; - strcat(string,rdf_head); - strcat(string,work_head); - - if (work_title) strcat(string,work_title); - if (work_date) strcat(string,work_date); - if (work_description) strcat(string,work_description); - if (work_creator) strcat(string,work_creator); - if (work_owner) strcat(string,work_owner); - if (work_source) strcat(string,work_source); - if (work_license) strcat(string,work_license); - - strcat(string,work_end); - if (license_head) { - strcat(string,license_head); - strcat(string,rdf->license->license_rdf); - strcat(string,license_end); - } - strcat(string,rdf_end); - - return string; -} -*/ - - -/** - * \brief Pull the text out of an RDF entity, depends on how it's stored - * \return A pointer to the entity's static contents as a string - * \param repr The XML element to extract from - * \param entity The desired RDF/Work entity - * - */ -const gchar * -rdf_get_repr_text ( Inkscape::XML::Node * repr, struct rdf_work_entity_t * entity ) -{ - g_return_val_if_fail (repr != NULL, NULL); - g_return_val_if_fail (entity != NULL, NULL); - static gchar * bag = NULL; - gchar * holder = NULL; - - Inkscape::XML::Node * temp=NULL; - switch (entity->datatype) { - case RDF_CONTENT: - temp = sp_repr_children(repr); - if ( temp == NULL ) return NULL; - - return temp->content(); - - case RDF_AGENT: - temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 ); - if ( temp == NULL ) return NULL; - - temp = sp_repr_lookup_name ( temp, "dc:title", 1 ); - if ( temp == NULL ) return NULL; - - temp = sp_repr_children(temp); - if ( temp == NULL ) return NULL; - - return temp->content(); - - case RDF_RESOURCE: - return repr->attribute("rdf:resource"); - - case RDF_XML: - return "xml goes here"; - - case RDF_BAG: - /* clear the static string. yucky. */ - if (bag) g_free(bag); - bag = NULL; - - temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 ); - if ( temp == NULL ) { - /* backwards compatible: read contents */ - temp = sp_repr_children(repr); - if ( temp == NULL ) return NULL; - - return temp->content(); - } - - for ( temp = sp_repr_children(temp) ; - temp ; - temp = sp_repr_next(temp) ) { - if (!strcmp(temp->name(),"rdf:li") && - temp->firstChild()) { - const gchar * str = temp->firstChild()->content(); - if (bag) { - holder = bag; - bag = g_strconcat(holder, ", ", str, NULL); - g_free(holder); - } - else { - bag = g_strdup(str); - } - } - } - return bag; - - default: - break; - } - return NULL; -} - -unsigned int -rdf_set_repr_text ( Inkscape::XML::Node * repr, - struct rdf_work_entity_t * entity, - gchar const * text ) -{ - g_return_val_if_fail ( repr != NULL, 0); - g_return_val_if_fail ( entity != NULL, 0); - g_return_val_if_fail ( text != NULL, 0); - gchar * str = NULL; - gchar** strlist = NULL; - int i; - - Inkscape::XML::Node * temp=NULL; - Inkscape::XML::Node * child=NULL; - Inkscape::XML::Node * parent=repr; - - Inkscape::XML::Document * xmldoc = parent->document(); - g_return_val_if_fail (xmldoc != NULL, FALSE); - - // set document's title element to the RDF title - if (!strcmp(entity->name, "title")) { - SPDocument *doc = SP_ACTIVE_DOCUMENT; - if(doc && doc->root) doc->root->setTitle(text); - } - - switch (entity->datatype) { - case RDF_CONTENT: - temp = sp_repr_children(parent); - if ( temp == NULL ) { - temp = xmldoc->createTextNode( text ); - g_return_val_if_fail (temp != NULL, FALSE); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - - return TRUE; - } - else { - temp->setContent(text); - return TRUE; - } - - case RDF_AGENT: - temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 ); - if ( temp == NULL ) { - temp = xmldoc->createElement ( "cc:Agent" ); - g_return_val_if_fail (temp != NULL, FALSE); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - } - parent = temp; - - temp = sp_repr_lookup_name ( parent, "dc:title", 1 ); - if ( temp == NULL ) { - temp = xmldoc->createElement ( "dc:title" ); - g_return_val_if_fail (temp != NULL, FALSE); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - } - parent = temp; - - temp = sp_repr_children(parent); - if ( temp == NULL ) { - temp = xmldoc->createTextNode( text ); - g_return_val_if_fail (temp != NULL, FALSE); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - - return TRUE; - } - else { - temp->setContent(text); - return TRUE; - } - - case RDF_RESOURCE: - parent->setAttribute("rdf:resource", text ); - return true; - - case RDF_XML: - return 1; - - case RDF_BAG: - /* find/create the rdf:Bag item */ - temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 ); - if ( temp == NULL ) { - /* backward compatibility: drop the dc:subject contents */ - while ( (temp = sp_repr_children( parent )) ) { - parent->removeChild(temp); - } - - temp = xmldoc->createElement ( "rdf:Bag" ); - g_return_val_if_fail (temp != NULL, FALSE); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - } - parent = temp; - - /* toss all the old list items */ - while ( (temp = sp_repr_children( parent )) ) { - parent->removeChild(temp); - } - - /* chop our list up on commas */ - strlist = g_strsplit( text, ",", 0); - - for (i = 0; (str = strlist[i]); i++) { - temp = xmldoc->createElement ( "rdf:li" ); - g_return_val_if_fail (temp != NULL, 0); - - parent->appendChild(temp); - Inkscape::GC::release(temp); - - child = xmldoc->createTextNode( g_strstrip(str) ); - g_return_val_if_fail (child != NULL, 0); - - temp->appendChild(child); - Inkscape::GC::release(child); - } - g_strfreev( strlist ); - - return 1; - - default: - break; - } - return 0; -} - -Inkscape::XML::Node * -rdf_get_rdf_root_repr ( SPDocument * doc, bool build ) -{ - g_return_val_if_fail (doc != NULL, NULL); - g_return_val_if_fail (doc->rroot != NULL, NULL); - - Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); - g_return_val_if_fail (xmldoc != NULL, NULL); - - Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF ); - - if (rdf == NULL) { - //printf("missing XML '%s'\n",XML_TAG_NAME_RDF); - if (!build) return NULL; - - Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG ); - g_return_val_if_fail ( svg != NULL, NULL ); - - Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA ); - if ( parent == NULL ) { - parent = xmldoc->createElement( XML_TAG_NAME_METADATA ); - g_return_val_if_fail ( parent != NULL, NULL); - - svg->appendChild(parent); - Inkscape::GC::release(parent); - } - - Inkscape::XML::Document * xmldoc = parent->document(); - g_return_val_if_fail (xmldoc != NULL, FALSE); - - rdf = xmldoc->createElement( XML_TAG_NAME_RDF ); - g_return_val_if_fail (rdf != NULL, NULL); - - parent->appendChild(rdf); - Inkscape::GC::release(rdf); - } - - /* - * some implementations do not put RDF stuff inside , - * so we need to check for it and add it if we don't see it - */ - Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf ); - g_return_val_if_fail (want_metadata != NULL, NULL); - if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) { - Inkscape::XML::Node * metadata = xmldoc->createElement( XML_TAG_NAME_METADATA ); - g_return_val_if_fail (metadata != NULL, NULL); - - /* attach the metadata node */ - want_metadata->appendChild(metadata); - Inkscape::GC::release(metadata); - - /* move the RDF into it */ - Inkscape::GC::anchor(rdf); - sp_repr_unparent ( rdf ); - metadata->appendChild(rdf); - Inkscape::GC::release(rdf); - } - - return rdf; -} - -Inkscape::XML::Node * -rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build ) -{ - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (doc != NULL, NULL); - g_return_val_if_fail (doc->rroot != NULL, NULL); - - Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build ); - if (!rdf) return NULL; - - Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name ); - if (xml == NULL) { - //printf("missing XML '%s'\n",name); - if (!build) return NULL; - - Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); - g_return_val_if_fail (xmldoc != NULL, NULL); - - xml = xmldoc->createElement( name ); - g_return_val_if_fail (xml != NULL, NULL); - - xml->setAttribute("rdf:about", "" ); - - rdf->appendChild(xml); - Inkscape::GC::release(xml); - } - - return xml; -} - -Inkscape::XML::Node * -rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build ) -{ - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (doc != NULL, NULL); - g_return_val_if_fail (doc->rroot != NULL, NULL); - - Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build ); - if (!work) return NULL; - - Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 ); - if (item == NULL) { - //printf("missing XML '%s'\n",name); - if (!build) return NULL; - - Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); - g_return_val_if_fail (xmldoc != NULL, NULL); - - item = xmldoc->createElement( name ); - g_return_val_if_fail (item != NULL, NULL); - - work->appendChild(item); - Inkscape::GC::release(item); - } - - return item; -} - - - -/** - * \brief Retrieves a known RDF/Work entity's contents from the document XML by name - * \return A pointer to the entity's static contents as a string, or NULL if no entity exists - * \param entity The desired RDF/Work entity - * - */ -const gchar * -rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity) -{ - g_return_val_if_fail (doc != NULL, NULL); - if ( entity == NULL ) return NULL; - //printf("want '%s'\n",entity->title); - bool bIsTitle = !strcmp(entity->name, "title"); - - Inkscape::XML::Node * item; - if ( entity->datatype == RDF_XML ) { - item = rdf_get_xml_repr ( doc, entity->tag, FALSE ); - } - else { - item = rdf_get_work_repr( doc, entity->tag, bIsTitle ); // build title if necessary - } - if ( item == NULL ) return NULL; - const gchar * result = rdf_get_repr_text ( item, entity ); - if(!result && bIsTitle && doc->root) { // if RDF title not set - result = doc->root->title(); // get the document's - rdf_set_work_entity(doc, entity, result); // and set the RDF - } - //printf("found '%s' == '%s'\n", entity->title, result ); - return result; -} - -/** - * \brief Stores a string into a named RDF/Work entity in the document XML - * \param entity The desired RDF/Work entity to replace - * \param string The string to replace the entity contents with - * - */ -unsigned int -rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity, - const gchar * text) -{ - g_return_val_if_fail ( entity != NULL, 0 ); - if (text == NULL) { - // FIXME: on a "NULL" text, delete the entity. For now, blank it. - text=""; - } - - /* - printf("changing '%s' (%s) to '%s'\n", - entity->title, - entity->tag, - text); - */ - - Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE ); - g_return_val_if_fail ( item != NULL, 0 ); - - return rdf_set_repr_text ( item, entity, text ); -} - -#undef DEBUG_MATCH - -static bool -rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license) -{ - g_assert ( repr != NULL ); - g_assert ( license != NULL ); - - bool result=TRUE; -#ifdef DEBUG_MATCH - printf("checking against '%s'\n",license->name); -#endif - - int count = 0; - for (struct rdf_double_t const *details = license->details; - details->name; details++ ) { - count++; - } - bool * matched = (bool*)calloc(count,sizeof(bool)); - - for (Inkscape::XML::Node const *current = sp_repr_children(repr); - current; - current = sp_repr_next ( current ) ) { - - gchar const * attr = current->attribute("rdf:resource"); - if ( attr == NULL ) continue; - -#ifdef DEBUG_MATCH - printf("\texamining '%s' => '%s'\n", current->name(), attr); -#endif - - bool found_match=FALSE; - for (int i=0; i<count; i++) { - // skip already matched items - if (matched[i]) continue; - -#ifdef DEBUG_MATCH - printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name); - printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource); -#endif - - if (!strcmp( current->name(), - license->details[i].name ) && - !strcmp( attr, - license->details[i].resource )) { - matched[i]=TRUE; - found_match=TRUE; -#ifdef DEBUG_MATCH - printf("\t\tgood!\n"); -#endif - break; - } - } - if (!found_match) { - // if we checked each known item of the license - // and didn't find it, we must abort - result=FALSE; -#ifdef DEBUG_MATCH - printf("\t\tno '%s' element matched XML (bong)!\n",license->name); -#endif - break; - } - } -#ifdef DEBUG_MATCH - if (result) printf("\t\tall XML found matching elements!\n"); -#endif - for (int i=0; result && i<count; i++) { - // scan looking for an unmatched item - if (matched[i]==0) { - result=FALSE; -#ifdef DEBUG_MATCH - printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name); -#endif - } - } - -#ifdef DEBUG_MATCH - printf("\t\tall '%s' elements used to match!\n",license->name); -#endif - - free(matched); - -#ifdef DEBUG_MATCH - if (result) printf("matched '%s'\n",license->name); -#endif - return result; -} - -/** - * \brief Attempts to match and retrieve a known RDF/License from the document XML - * \return A pointer to the static RDF license structure - * - */ -struct rdf_license_t * -rdf_get_license(SPDocument * document) -{ - Inkscape::XML::Node const *repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE ); - if (repr) { - for (struct rdf_license_t * license = rdf_licenses; - license->name; license++ ) { - if ( rdf_match_license ( repr, license ) ) return license; - } - } -#ifdef DEBUG_MATCH - else { - printf("no license XML\n"); - } -#endif - return NULL; -} - -/** - * \brief Stores an RDF/License XML in the document XML - * \param document Which document to update - * \param license The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license. - * - */ -void -rdf_set_license(SPDocument * doc, struct rdf_license_t const * license) -{ - // drop old license section - Inkscape::XML::Node * repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, FALSE ); - if (repr) sp_repr_unparent(repr); - - if (!license) return; - - // build new license section - repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, TRUE ); - g_assert ( repr ); - - repr->setAttribute("rdf:about", license->uri ); - - Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); - g_return_if_fail (xmldoc != NULL); - - for (struct rdf_double_t const * detail = license->details; - detail->name; detail++) { - Inkscape::XML::Node * child = xmldoc->createElement( detail->name ); - g_assert ( child != NULL ); - - child->setAttribute("rdf:resource", detail->resource ); - repr->appendChild(child); - Inkscape::GC::release(child); - } -} - -struct rdf_entity_default_t { - gchar const * name; - gchar const * text; -}; -struct rdf_entity_default_t rdf_defaults[] = { - { "format", "image/svg+xml", }, - { "type", "http://purl.org/dc/dcmitype/StillImage", }, - { NULL, NULL, } -}; - -void -rdf_set_defaults ( SPDocument * doc ) -{ - g_assert ( doc != NULL ); - - // Create metadata node if it doesn't already exist - if (!sp_item_group_get_child_by_name ((SPGroup *) doc->root, NULL, - XML_TAG_NAME_METADATA)) { - // create repr - Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); - g_return_if_fail (xmldoc != NULL); - Inkscape::XML::Node * rnew = xmldoc->createElement (XML_TAG_NAME_METADATA); - // insert into the document - doc->rroot->addChild(rnew, NULL); - // clean up - Inkscape::GC::release(rnew); - } - - /* install defaults */ - for ( struct rdf_entity_default_t * rdf_default = rdf_defaults; - rdf_default->name; - rdf_default++) { - struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name ); - g_assert ( entity != NULL ); - - if ( rdf_get_work_entity ( doc, entity ) == NULL ) { - rdf_set_work_entity ( doc, entity, rdf_default->text ); - } - } -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/rdf.h b/src/dialogs/rdf.h deleted file mode 100644 index a98f5a1e4..000000000 --- a/src/dialogs/rdf.h +++ /dev/null @@ -1,120 +0,0 @@ -/** @file - * @brief headers for RDF types - */ -/* Authors: - * Kees Cook <kees@outflux.net> - * - * Copyright (C) 2004 Authors - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef _RDF_H_ -#define _RDF_H_ - -#include <glib.h> -#include <glibmm/i18n.h> -#include "document.h" - -// yeah, it's not a triple yet... -/** - * \brief Holds license name/resource doubles for rdf_license_t entries - */ -struct rdf_double_t { - gchar const *name; - gchar const *resource; -}; - -/** - * \brief Holds license name and RDF information - */ -struct rdf_license_t { - gchar const *name; /* localized name of this license */ - gchar const *uri; /* URL for the RDF/Work/license element */ - struct rdf_double_t *details; /* the license details */ -// gchar const *fragment; /* XML contents for the RDF/License tag */ -}; - -extern rdf_license_t rdf_licenses []; - -/** - * \brief Describes how a given RDF entity is stored in XML - */ -enum RDFType { - RDF_CONTENT, // direct between-XML-tags content - RDF_AGENT, // requires the "Agent" hierarchy before doing content - RDF_RESOURCE, // stored in "rdf:resource" element - RDF_XML, // literal XML - RDF_BAG // rdf:Bag resources -}; - -/** - * \brief Describes how a given RDF entity should be edited - */ -enum RDF_Format { - RDF_FORMAT_LINE, // uses single line data (GtkEntry) - RDF_FORMAT_MULTILINE, // uses multiline data (GtkTextView) - RDF_FORMAT_SPECIAL // uses some other edit methods -}; - -enum RDF_Editable { - RDF_EDIT_GENERIC, // editable via generic widgets - RDF_EDIT_SPECIAL, // special widgets are needed - RDF_EDIT_HARDCODED // isn't editable -}; - -/** - * \brief Holds known RDF/Work tags - */ -struct rdf_work_entity_t { - char const *name; /* unique name of this entity for internal reference */ - gchar const *title; /* localized title of this entity for data entry */ - gchar const *tag; /* namespace tag for the RDF/Work element */ - RDFType datatype; /* how to extract/inject the RDF information */ - gchar const *tip; /* tool tip to explain the meaning of the entity */ - RDF_Format format; /* in what format is this data edited? */ - RDF_Editable editable;/* in what way is the data editable? */ -}; - -extern rdf_work_entity_t rdf_work_entities []; - -/** - * \brief Generic collection of RDF information for the RDF debug function - */ -struct rdf_t { - gchar* work_title; - gchar* work_date; - gchar* work_creator; - gchar* work_owner; - gchar* work_publisher; - gchar* work_type; - gchar* work_source; - gchar* work_subject; - gchar* work_description; - struct rdf_license_t* license; -}; - -struct rdf_work_entity_t * rdf_find_entity(gchar const * name); - -const gchar * rdf_get_work_entity(SPDocument * doc, - struct rdf_work_entity_t * entity); -unsigned int rdf_set_work_entity(SPDocument * doc, - struct rdf_work_entity_t * entity, - const gchar * text); - -struct rdf_license_t * rdf_get_license(SPDocument * doc); -void rdf_set_license(SPDocument * doc, - struct rdf_license_t const * license); - -void rdf_set_defaults ( SPDocument * doc ); - -#endif // _RDF_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/sp-attribute-widget.cpp b/src/dialogs/sp-attribute-widget.cpp deleted file mode 100644 index de14fc173..000000000 --- a/src/dialogs/sp-attribute-widget.cpp +++ /dev/null @@ -1,790 +0,0 @@ -/** @file - * @brief Widget that listens and modifies repr attributes - */ -/* Authors: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Ximian, Inc. - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <gtk/gtktable.h> -#include <gtk/gtklabel.h> -#include "xml/repr.h" -#include "macros.h" -#include "document.h" -#include "sp-object.h" -#include <glibmm/i18n.h> - -#include <sigc++/functors/ptr_fun.h> -#include <sigc++/adaptors/bind.h> - -#include "sp-attribute-widget.h" - -static void sp_attribute_widget_class_init (SPAttributeWidgetClass *klass); -static void sp_attribute_widget_init (SPAttributeWidget *widget); -static void sp_attribute_widget_destroy (GtkObject *object); - -static void sp_attribute_widget_changed (GtkEditable *editable); - -static void sp_attribute_widget_object_modified ( SPObject *object, - guint flags, - SPAttributeWidget *spaw ); -static void sp_attribute_widget_object_release ( SPObject *object, - SPAttributeWidget *spaw ); - -static GtkEntryClass *parent_class; - - - - -GType sp_attribute_widget_get_type(void) -{ - static GtkType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPAttributeWidgetClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_attribute_widget_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPAttributeWidget), - 0, // n_preallocs - (GInstanceInitFunc)sp_attribute_widget_init, - 0 // value_table - }; - type = g_type_register_static(GTK_TYPE_ENTRY, "SPAttributeWidget", &info, static_cast<GTypeFlags>(0)); - } - return type; -} // end of sp_attribute_widget_get_type() - - - -static void -sp_attribute_widget_class_init (SPAttributeWidgetClass *klass) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkEditableClass *editable_class; - - object_class = GTK_OBJECT_CLASS (klass); - widget_class = GTK_WIDGET_CLASS (klass); - editable_class = GTK_EDITABLE_CLASS (klass); - - parent_class = (GtkEntryClass*)gtk_type_class (GTK_TYPE_ENTRY); - - object_class->destroy = sp_attribute_widget_destroy; - - editable_class->changed = sp_attribute_widget_changed; - -} // end of sp_attribute_widget_class_init() - - - -static void -sp_attribute_widget_init (SPAttributeWidget *spaw) -{ - spaw->blocked = FALSE; - spaw->hasobj = FALSE; - - spaw->src.object = NULL; - - spaw->attribute = NULL; - - new (&spaw->modified_connection) sigc::connection(); - new (&spaw->release_connection) sigc::connection(); -} - - - -static void -sp_attribute_widget_destroy (GtkObject *object) -{ - - SPAttributeWidget *spaw; - - spaw = SP_ATTRIBUTE_WIDGET (object); - - if (spaw->attribute) { - g_free (spaw->attribute); - spaw->attribute = NULL; - } - - - if (spaw->hasobj) { - - if (spaw->src.object) { - spaw->modified_connection.disconnect(); - spaw->release_connection.disconnect(); - spaw->src.object = NULL; - } - } else { - - if (spaw->src.repr) { - spaw->src.repr = Inkscape::GC::release(spaw->src.repr); - } - } // end of if() - - spaw->modified_connection.~connection(); - spaw->release_connection.~connection(); - - ((GtkObjectClass *) parent_class)->destroy (object); - -} - - - -static void -sp_attribute_widget_changed (GtkEditable *editable) -{ - - SPAttributeWidget *spaw; - - spaw = SP_ATTRIBUTE_WIDGET (editable); - - if (!spaw->blocked) { - - const gchar *text; - spaw->blocked = TRUE; - text = gtk_entry_get_text (GTK_ENTRY (spaw)); - if (!*text) - text = NULL; - - if (spaw->hasobj && spaw->src.object) { - - SP_OBJECT_REPR (spaw->src.object)->setAttribute(spaw->attribute, text, false); - sp_document_done (SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE, - _("Set attribute")); - - } else if (spaw->src.repr) { - - spaw->src.repr->setAttribute(spaw->attribute, text, false); - /* TODO: Warning! Undo will not be flushed in given case */ - } - spaw->blocked = FALSE; - } - -} // end of sp_attribute_widget_changed() - - - -GtkWidget * -sp_attribute_widget_new ( SPObject *object, const gchar *attribute ) -{ - SPAttributeWidget *spaw; - - g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL); - g_return_val_if_fail (!object || attribute, NULL); - - spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET); - - sp_attribute_widget_set_object (spaw, object, attribute); - - return GTK_WIDGET (spaw); - -} // end of sp_attribute_widget_new() - - - -GtkWidget * -sp_attribute_widget_new_repr ( Inkscape::XML::Node *repr, const gchar *attribute ) -{ - SPAttributeWidget *spaw; - - spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET); - - sp_attribute_widget_set_repr (spaw, repr, attribute); - - return GTK_WIDGET (spaw); -} - - - -void -sp_attribute_widget_set_object ( SPAttributeWidget *spaw, - SPObject *object, - const gchar *attribute ) -{ - - g_return_if_fail (spaw != NULL); - g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw)); - g_return_if_fail (!object || SP_IS_OBJECT (object)); - g_return_if_fail (!object || attribute); - g_return_if_fail (attribute != NULL); - - if (spaw->attribute) { - g_free (spaw->attribute); - spaw->attribute = NULL; - } - - if (spaw->hasobj) { - - if (spaw->src.object) { - spaw->modified_connection.disconnect(); - spaw->release_connection.disconnect(); - spaw->src.object = NULL; - } - } else { - - if (spaw->src.repr) { - spaw->src.repr = Inkscape::GC::release(spaw->src.repr); - } - } - - spaw->hasobj = TRUE; - - if (object) { - const gchar *val; - - spaw->blocked = TRUE; - spaw->src.object = object; - - spaw->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_widget_object_modified), spaw)); - spaw->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_widget_object_release), spaw)); - - spaw->attribute = g_strdup (attribute); - - val = SP_OBJECT_REPR (object)->attribute(attribute); - gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) ""); - spaw->blocked = FALSE; - } - - gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.object != NULL)); - -} // end of sp_attribute_widget_set_object() - - - -void -sp_attribute_widget_set_repr ( SPAttributeWidget *spaw, - Inkscape::XML::Node *repr, - const gchar *attribute ) -{ - - g_return_if_fail (spaw != NULL); - g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw)); - g_return_if_fail (attribute != NULL); - - if (spaw->attribute) { - g_free (spaw->attribute); - spaw->attribute = NULL; - } - - if (spaw->hasobj) { - - if (spaw->src.object) { - spaw->modified_connection.disconnect(); - spaw->release_connection.disconnect(); - spaw->src.object = NULL; - } - } else { - - if (spaw->src.repr) { - spaw->src.repr = Inkscape::GC::release(spaw->src.repr); - } - } - - spaw->hasobj = FALSE; - - if (repr) { - const gchar *val; - - spaw->blocked = TRUE; - spaw->src.repr = Inkscape::GC::anchor(repr); - spaw->attribute = g_strdup (attribute); - - val = repr->attribute(attribute); - gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) ""); - spaw->blocked = FALSE; - } - - gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.repr != NULL)); - -} // end of sp_attribute_widget_set_repr() - - - -static void -sp_attribute_widget_object_modified ( SPObject */*object*/, - guint flags, - SPAttributeWidget *spaw ) -{ - - if (flags && SP_OBJECT_MODIFIED_FLAG) { - - const gchar *val, *text; - val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute); - text = gtk_entry_get_text (GTK_ENTRY (spaw)); - - if (val || text) { - - if (!val || !text || strcmp (val, text)) { - /* We are different */ - spaw->blocked = TRUE; - gtk_entry_set_text ( GTK_ENTRY (spaw), - val ? val : (const gchar *) ""); - spaw->blocked = FALSE; - } // end of if() - - } // end of if() - - } //end of if() - -} // end of sp_attribute_widget_object_modified() - - - -static void -sp_attribute_widget_object_release ( SPObject */*object*/, - SPAttributeWidget *spaw ) -{ - sp_attribute_widget_set_object (spaw, NULL, NULL); -} - - - -/* SPAttributeTable */ - -static void sp_attribute_table_class_init (SPAttributeTableClass *klass); -static void sp_attribute_table_init (SPAttributeTable *widget); -static void sp_attribute_table_destroy (GtkObject *object); - -static void sp_attribute_table_object_modified (SPObject *object, guint flags, SPAttributeTable *spaw); -static void sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spaw); -static void sp_attribute_table_entry_changed (GtkEditable *editable, SPAttributeTable *spat); - -static GtkVBoxClass *table_parent_class; - - - - -GType sp_attribute_table_get_type(void) -{ - static GtkType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPAttributeTableClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_attribute_table_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPAttributeTable), - 0, // n_preallocs - (GInstanceInitFunc)sp_attribute_table_init, - 0 // value_table - }; - type = g_type_register_static(GTK_TYPE_VBOX, "SPAttributeTable", &info, static_cast<GTypeFlags>(0)); - } - return type; -} // end of sp_attribute_table_get_type() - - - -static void -sp_attribute_table_class_init (SPAttributeTableClass *klass) -{ - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = GTK_OBJECT_CLASS (klass); - widget_class = GTK_WIDGET_CLASS (klass); - - table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX); - - object_class->destroy = sp_attribute_table_destroy; - -} // end of sp_attribute_table_class_init() - - - -static void -sp_attribute_table_init ( SPAttributeTable *spat ) -{ - spat->blocked = FALSE; - spat->hasobj = FALSE; - spat->table = NULL; - spat->src.object = NULL; - spat->num_attr = 0; - spat->attributes = NULL; - spat->entries = NULL; - - new (&spat->modified_connection) sigc::connection(); - new (&spat->release_connection) sigc::connection(); -} - -static void -sp_attribute_table_destroy ( GtkObject *object ) -{ - SPAttributeTable *spat; - - spat = SP_ATTRIBUTE_TABLE (object); - - if (spat->attributes) { - gint i; - for (i = 0; i < spat->num_attr; i++) { - g_free (spat->attributes[i]); - } - g_free (spat->attributes); - spat->attributes = NULL; - } - - if (spat->hasobj) { - - if (spat->src.object) { - spat->modified_connection.disconnect(); - spat->release_connection.disconnect(); - spat->src.object = NULL; - } - } else { - if (spat->src.repr) { - spat->src.repr = Inkscape::GC::release(spat->src.repr); - } - } // end of if() - - spat->modified_connection.~connection(); - spat->release_connection.~connection(); - - if (spat->entries) { - g_free (spat->entries); - spat->entries = NULL; - } - - spat->table = NULL; - - if (((GtkObjectClass *) table_parent_class)->destroy) { - (* ((GtkObjectClass *) table_parent_class)->destroy) (object); - } - -} // end of sp_attribute_table_destroy() - - -GtkWidget * -sp_attribute_table_new ( SPObject *object, - gint num_attr, - const gchar **labels, - const gchar **attributes ) -{ - SPAttributeTable *spat; - - g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL); - g_return_val_if_fail (!object || (num_attr > 0), NULL); - g_return_val_if_fail (!num_attr || (labels && attributes), NULL); - - spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE); - - sp_attribute_table_set_object (spat, object, num_attr, labels, attributes); - - return GTK_WIDGET (spat); - -} // end of sp_attribute_table_new() - - - -GtkWidget * -sp_attribute_table_new_repr ( Inkscape::XML::Node *repr, - gint num_attr, - const gchar **labels, - const gchar **attributes ) -{ - SPAttributeTable *spat; - - g_return_val_if_fail (!num_attr || (labels && attributes), NULL); - - spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE); - - sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes); - - return GTK_WIDGET (spat); - -} // end of sp_attribute_table_new_repr() - - - -#define XPAD 4 -#define YPAD 0 - -void -sp_attribute_table_set_object ( SPAttributeTable *spat, - SPObject *object, - gint num_attr, - const gchar **labels, - const gchar **attributes ) -{ - - g_return_if_fail (spat != NULL); - g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat)); - g_return_if_fail (!object || SP_IS_OBJECT (object)); - g_return_if_fail (!object || (num_attr > 0)); - g_return_if_fail (!num_attr || (labels && attributes)); - - if (spat->table) { - gtk_widget_destroy (spat->table); - spat->table = NULL; - } - - if (spat->attributes) { - gint i; - for (i = 0; i < spat->num_attr; i++) { - g_free (spat->attributes[i]); - } - g_free (spat->attributes); - spat->attributes = NULL; - } - - if (spat->entries) { - g_free (spat->entries); - spat->entries = NULL; - } - - if (spat->hasobj) { - if (spat->src.object) { - spat->modified_connection.disconnect(); - spat->release_connection.disconnect(); - spat->src.object = NULL; - } - } else { - if (spat->src.repr) { - spat->src.repr = Inkscape::GC::release(spat->src.repr); - } - } - - spat->hasobj = TRUE; - - if (object) { - gint i; - - spat->blocked = TRUE; - - /* Set up object */ - spat->src.object = object; - spat->num_attr = num_attr; - - spat->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_table_object_modified), spat)); - spat->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_table_object_release), spat)); - - /* Create table */ - spat->table = gtk_table_new (num_attr, 2, FALSE); - gtk_container_add (GTK_CONTAINER (spat), spat->table); - /* Arrays */ - spat->attributes = g_new0 (gchar *, num_attr); - spat->entries = g_new0 (GtkWidget *, num_attr); - /* Fill rows */ - for (i = 0; i < num_attr; i++) { - GtkWidget *w; - const gchar *val; - - spat->attributes[i] = g_strdup (attributes[i]); - w = gtk_label_new (_(labels[i])); - gtk_widget_show (w); - gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); - gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1, - GTK_FILL, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - XPAD, YPAD ); - w = gtk_entry_new (); - gtk_widget_show (w); - val = SP_OBJECT_REPR (object)->attribute(attributes[i]); - gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) ""); - gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - XPAD, YPAD ); - spat->entries[i] = w; - g_signal_connect ( G_OBJECT (w), "changed", - G_CALLBACK (sp_attribute_table_entry_changed), - spat ); - } - /* Show table */ - gtk_widget_show (spat->table); - - spat->blocked = FALSE; - } - - gtk_widget_set_sensitive ( GTK_WIDGET (spat), - (spat->src.object != NULL) ); - -} // end of sp_attribute_table_set_object() - - - -void -sp_attribute_table_set_repr ( SPAttributeTable *spat, - Inkscape::XML::Node *repr, - gint num_attr, - const gchar **labels, - const gchar **attributes ) -{ - g_return_if_fail (spat != NULL); - g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat)); - g_return_if_fail (!num_attr || (labels && attributes)); - - if (spat->table) { - gtk_widget_destroy (spat->table); - spat->table = NULL; - } - - if (spat->attributes) { - gint i; - for (i = 0; i < spat->num_attr; i++) { - g_free (spat->attributes[i]); - } - g_free (spat->attributes); - spat->attributes = NULL; - } - - if (spat->entries) { - g_free (spat->entries); - spat->entries = NULL; - } - - if (spat->hasobj) { - if (spat->src.object) { - spat->modified_connection.disconnect(); - spat->release_connection.disconnect(); - spat->src.object = NULL; - } - } else { - if (spat->src.repr) { - spat->src.repr = Inkscape::GC::release(spat->src.repr); - } - } - - spat->hasobj = FALSE; - - if (repr) { - gint i; - - spat->blocked = TRUE; - - /* Set up repr */ - spat->src.repr = Inkscape::GC::anchor(repr); - spat->num_attr = num_attr; - /* Create table */ - spat->table = gtk_table_new (num_attr, 2, FALSE); - gtk_container_add (GTK_CONTAINER (spat), spat->table); - /* Arrays */ - spat->attributes = g_new0 (gchar *, num_attr); - spat->entries = g_new0 (GtkWidget *, num_attr); - - /* Fill rows */ - for (i = 0; i < num_attr; i++) { - GtkWidget *w; - const gchar *val; - - spat->attributes[i] = g_strdup (attributes[i]); - w = gtk_label_new (labels[i]); - gtk_widget_show (w); - gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); - gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1, - GTK_FILL, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - XPAD, YPAD ); - w = gtk_entry_new (); - gtk_widget_show (w); - val = repr->attribute(attributes[i]); - gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) ""); - gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), - XPAD, YPAD ); - spat->entries[i] = w; - g_signal_connect ( G_OBJECT (w), "changed", - G_CALLBACK (sp_attribute_table_entry_changed), - spat ); - } - /* Show table */ - gtk_widget_show (spat->table); - - spat->blocked = FALSE; - } - - gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL)); - -} // end of sp_attribute_table_set_repr() - - - -static void -sp_attribute_table_object_modified ( SPObject */*object*/, - guint flags, - SPAttributeTable *spat ) -{ - if (flags && SP_OBJECT_MODIFIED_FLAG) - { - gint i; - for (i = 0; i < spat->num_attr; i++) { - const gchar *val, *text; - val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]); - text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i])); - if (val || text) { - if (!val || !text || strcmp (val, text)) { - /* We are different */ - spat->blocked = TRUE; - gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]), - val ? val : (const gchar *) ""); - spat->blocked = FALSE; - } - } - } - } // end of if() - -} // end of sp_attribute_table_object_modified() - - - -static void -sp_attribute_table_object_release (SPObject */*object*/, SPAttributeTable *spat) -{ - sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL); -} - - - -static void -sp_attribute_table_entry_changed ( GtkEditable *editable, - SPAttributeTable *spat ) -{ - if (!spat->blocked) - { - gint i; - for (i = 0; i < spat->num_attr; i++) { - - if (GTK_WIDGET (editable) == spat->entries[i]) { - const gchar *text; - spat->blocked = TRUE; - text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i])); - - if (!*text) - text = NULL; - - if (spat->hasobj && spat->src.object) { - SP_OBJECT_REPR (spat->src.object)->setAttribute(spat->attributes[i], text, false); - sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE, - _("Set attribute")); - - } else if (spat->src.repr) { - - spat->src.repr->setAttribute(spat->attributes[i], text, false); - /* TODO: Warning! Undo will not be flushed in given case */ - } - spat->blocked = FALSE; - return; - } - } - g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__); - } // end of if() - -} // end of sp_attribute_table_entry_changed() - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/sp-attribute-widget.h b/src/dialogs/sp-attribute-widget.h deleted file mode 100644 index 01da29bed..000000000 --- a/src/dialogs/sp-attribute-widget.h +++ /dev/null @@ -1,130 +0,0 @@ -/** @file - * @brief Widget that listens and modifies repr attributes - */ -/* Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * Copyright (C) 2002 authors - * Copyright (C) 2001 Ximian, Inc. - * - * Licensed under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H -#define SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H - -#include <glib.h> -#include <sigc++/connection.h> - -#define SP_TYPE_ATTRIBUTE_WIDGET (sp_attribute_widget_get_type ()) -#define SP_ATTRIBUTE_WIDGET(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_ATTRIBUTE_WIDGET, SPAttributeWidget)) -#define SP_ATTRIBUTE_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_ATTRIBUTE_WIDGET, SPAttributeWidgetClass)) -#define SP_IS_ATTRIBUTE_WIDGET(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_ATTRIBUTE_WIDGET)) -#define SP_IS_ATTRIBUTE_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_ATTRIBUTE_WIDGET)) - -#define SP_TYPE_ATTRIBUTE_TABLE (sp_attribute_table_get_type ()) -#define SP_ATTRIBUTE_TABLE(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_ATTRIBUTE_TABLE, SPAttributeTable)) -#define SP_ATTRIBUTE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_ATTRIBUTE_TABLE, SPAttributeTableClass)) -#define SP_IS_ATTRIBUTE_TABLE(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_ATTRIBUTE_TABLE)) -#define SP_IS_ATTRIBUTE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_ATTRIBUTE_TABLE)) - -namespace Inkscape { -namespace XML { -class Node; -} -} - - -struct SPAttributeWidget; -struct SPAttributeWidgetClass; - -struct SPAttributeTable; -struct SPAttributeTableClass; - -#include <gtk/gtkentry.h> -#include <gtk/gtkvbox.h> - -#include <forward.h> - -struct SPAttributeWidget { - GtkEntry entry; - guint blocked : 1; - guint hasobj : 1; - union { - SPObject *object; - Inkscape::XML::Node *repr; - } src; - gchar *attribute; - - sigc::connection modified_connection; - sigc::connection release_connection; -}; - -struct SPAttributeWidgetClass { - GtkEntryClass entry_class; -}; - -GtkType sp_attribute_widget_get_type (void); - -GtkWidget *sp_attribute_widget_new (SPObject *object, const gchar *attribute); -GtkWidget *sp_attribute_widget_new_repr (Inkscape::XML::Node *repr, const gchar *attribute); - -void sp_attribute_widget_set_object ( SPAttributeWidget *spw, - SPObject *object, - const gchar *attribute ); -void sp_attribute_widget_set_repr ( SPAttributeWidget *spw, - Inkscape::XML::Node *repr, - const gchar *attribute ); - -/* SPAttributeTable */ - -struct SPAttributeTable { - GtkVBox vbox; - guint blocked : 1; - guint hasobj : 1; - GtkWidget *table; - union { - SPObject *object; - Inkscape::XML::Node *repr; - } src; - gint num_attr; - gchar **attributes; - GtkWidget **entries; - - sigc::connection modified_connection; - sigc::connection release_connection; -}; - -struct SPAttributeTableClass { - GtkEntryClass entry_class; -}; - -GtkType sp_attribute_table_get_type (void); - -GtkWidget *sp_attribute_table_new ( SPObject *object, gint num_attr, - const gchar **labels, - const gchar **attributes ); -GtkWidget *sp_attribute_table_new_repr ( Inkscape::XML::Node *repr, gint num_attr, - const gchar **labels, - const gchar **attributes ); -void sp_attribute_table_set_object ( SPAttributeTable *spw, - SPObject *object, gint num_attr, - const gchar **labels, - const gchar **attrs ); -void sp_attribute_table_set_repr ( SPAttributeTable *spw, - Inkscape::XML::Node *repr, gint num_attr, - const gchar **labels, - const gchar **attrs ); - -#endif - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/stroke-style.cpp b/src/dialogs/stroke-style.cpp deleted file mode 100644 index 566ee5117..000000000 --- a/src/dialogs/stroke-style.cpp +++ /dev/null @@ -1,1838 +0,0 @@ -/** @file - * @brief Stroke style dialog - */ -/* Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * Bryce Harrington <brycehar@bryceharrington.org> - * bulia byak <buliabyak@users.sf.net> - * Maximilian Albert <maximilian.albert@gmail.com> - * Josh Andler <scislac@users.sf.net> - * - * Copyright (C) 2001-2005 authors - * Copyright (C) 2001 Ximian, Inc. - * Copyright (C) 2004 John Cliff - * Copyright (C) 2008 Maximilian Albert (gtkmm-ification) - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#define noSP_SS_VERBOSE - -#include <glib/gmem.h> -#include <gtk/gtk.h> -#include <glibmm/i18n.h> - -#include "desktop-handles.h" -#include "desktop-style.h" -#include "dialogs/dialog-events.h" -#include "display/nr-arena.h" -#include "display/nr-arena-item.h" -#include "document-private.h" -#include "gradient-chemistry.h" -#include "helper/stock-items.h" -#include "helper/unit-menu.h" -#include "helper/units.h" -#include "inkscape.h" -#include "io/sys.h" -#include "marker.h" -#include "path-prefix.h" -#include "selection.h" -#include "sp-linear-gradient.h" -#include "sp-namedview.h" -#include "sp-pattern.h" -#include "sp-radial-gradient.h" -#include "sp-rect.h" -#include "sp-text.h" -#include "style.h" -#include "svg/css-ostringstream.h" -#include "ui/cache/svg_preview_cache.h" -#include "ui/icon-names.h" -#include "widgets/dash-selector.h" -#include "widgets/icon.h" -#include "widgets/paint-selector.h" -#include "widgets/sp-widget.h" -#include "widgets/spw-utilities.h" -#include "xml/repr.h" - -#include "dialogs/stroke-style.h" - - -/* Paint */ - -static void sp_stroke_style_paint_selection_modified (SPWidget *spw, Inkscape::Selection *selection, guint flags, SPPaintSelector *psel); -static void sp_stroke_style_paint_selection_changed (SPWidget *spw, Inkscape::Selection *selection, SPPaintSelector *psel); -static void sp_stroke_style_paint_update(SPWidget *spw); - -static void sp_stroke_style_paint_mode_changed(SPPaintSelector *psel, SPPaintSelectorMode mode, SPWidget *spw); -static void sp_stroke_style_paint_dragged(SPPaintSelector *psel, SPWidget *spw); -static void sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw); - -static void sp_stroke_style_widget_change_subselection ( Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw ); -static void sp_stroke_style_widget_transientize_callback(Inkscape::Application *inkscape, - SPDesktop *desktop, - SPWidget *spw ); - -/** 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 SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); -static void ink_markers_menu_update(Gtk::Container* spw, SPMarkerLoc const which); - -static Inkscape::UI::Cache::SvgPreview svg_preview_cache; - -/** - * Create the stroke style widget, and hook up all the signals. - */ -GtkWidget * -sp_stroke_style_paint_widget_new(void) -{ - GtkWidget *spw, *psel; - - spw = sp_widget_new_global(INKSCAPE); - - psel = sp_paint_selector_new(false); // without fillrule selector - gtk_widget_show(psel); - gtk_container_add(GTK_CONTAINER(spw), psel); - gtk_object_set_data(GTK_OBJECT(spw), "paint-selector", psel); - - gtk_signal_connect(GTK_OBJECT(spw), "modify_selection", - GTK_SIGNAL_FUNC(sp_stroke_style_paint_selection_modified), - psel); - gtk_signal_connect(GTK_OBJECT(spw), "change_selection", - GTK_SIGNAL_FUNC(sp_stroke_style_paint_selection_changed), - psel); - - g_signal_connect (INKSCAPE, "change_subselection", G_CALLBACK (sp_stroke_style_widget_change_subselection), spw); - - g_signal_connect (G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK (sp_stroke_style_widget_transientize_callback), spw ); - - gtk_signal_connect(GTK_OBJECT(psel), "mode_changed", - GTK_SIGNAL_FUNC(sp_stroke_style_paint_mode_changed), - spw); - gtk_signal_connect(GTK_OBJECT(psel), "dragged", - GTK_SIGNAL_FUNC(sp_stroke_style_paint_dragged), - spw); - gtk_signal_connect(GTK_OBJECT(psel), "changed", - GTK_SIGNAL_FUNC(sp_stroke_style_paint_changed), - spw); - - sp_stroke_style_paint_update (SP_WIDGET(spw)); - return spw; -} - -/** - * On signal modified, invokes an update of the stroke style paint object. - */ -static void -sp_stroke_style_paint_selection_modified( SPWidget *spw, - Inkscape::Selection */*selection*/, - guint flags, - SPPaintSelector */*psel*/ ) -{ - if (flags & ( SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG | - SP_OBJECT_STYLE_MODIFIED_FLAG) ) { - sp_stroke_style_paint_update(spw); - } -} - - -/** - * On signal selection changed, invokes an update of the stroke style paint object. - */ -static void -sp_stroke_style_paint_selection_changed( SPWidget *spw, - Inkscape::Selection */*selection*/, - SPPaintSelector */*psel*/ ) -{ - sp_stroke_style_paint_update (spw); -} - - -/** - * On signal change subselection, invoke an update of the stroke style widget. - */ -static void -sp_stroke_style_widget_change_subselection( Inkscape::Application */*inkscape*/, - SPDesktop */*desktop*/, - SPWidget *spw ) -{ - sp_stroke_style_paint_update (spw); -} - -/** - * Gets the active stroke style property, then sets the appropriate color, alpha, gradient, - * pattern, etc. for the paint-selector. - */ -static void -sp_stroke_style_paint_update (SPWidget *spw) -{ - if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { - return; - } - - gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(TRUE)); - - SPPaintSelector *psel = SP_PAINT_SELECTOR(gtk_object_get_data(GTK_OBJECT(spw), "paint-selector")); - - // create temporary style - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - // query into it - int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKE); - - switch (result) { - case QUERY_STYLE_NOTHING: - { - /* No paint at all */ - sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_EMPTY); - break; - } - - case QUERY_STYLE_SINGLE: - case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector - case QUERY_STYLE_MULTIPLE_SAME: - { - SPPaintSelectorMode pselmode = sp_style_determine_paint_selector_mode (query, false); - sp_paint_selector_set_mode (psel, pselmode); - - if (query->stroke.set && query->stroke.isPaintserver()) { - - SPPaintServer *server = SP_STYLE_STROKE_SERVER (query); - - if (SP_IS_LINEARGRADIENT (server)) { - SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); - sp_paint_selector_set_gradient_linear (psel, vector); - - SPLinearGradient *lg = SP_LINEARGRADIENT (server); - sp_paint_selector_set_gradient_properties (psel, - SP_GRADIENT_UNITS (lg), - SP_GRADIENT_SPREAD (lg)); - } else if (SP_IS_RADIALGRADIENT (server)) { - SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); - sp_paint_selector_set_gradient_radial (psel, vector); - - SPRadialGradient *rg = SP_RADIALGRADIENT (server); - sp_paint_selector_set_gradient_properties (psel, - SP_GRADIENT_UNITS (rg), - SP_GRADIENT_SPREAD (rg)); - } else if (SP_IS_PATTERN (server)) { - SPPattern *pat = pattern_getroot (SP_PATTERN (server)); - sp_update_pattern_list (psel, pat); - } - } else if (query->stroke.set && query->stroke.isColor()) { - sp_paint_selector_set_color_alpha (psel, &query->stroke.value.color, SP_SCALE24_TO_FLOAT (query->stroke_opacity.value)); - - } - break; - } - - case QUERY_STYLE_MULTIPLE_DIFFERENT: - { - sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_MULTIPLE); - break; - } - } - - sp_style_unref(query); - - gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); -} - -/** - * When the mode is changed, invoke a regular changed handler. - */ -static void -sp_stroke_style_paint_mode_changed( SPPaintSelector *psel, - SPPaintSelectorMode /*mode*/, - SPWidget *spw ) -{ - if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { - return; - } - - /* TODO: Does this work? - * Not really, here we have to get old color back from object - * Instead of relying on paint widget having meaningful colors set - */ - sp_stroke_style_paint_changed(psel, spw); -} - -static gchar const *const undo_label_1 = "stroke:flatcolor:1"; -static gchar const *const undo_label_2 = "stroke:flatcolor:2"; -static gchar const *undo_label = undo_label_1; - -/** - * When a drag callback occurs on a paint selector object, if it is a RGB or CMYK - * color mode, then set the stroke opacity to psel's flat color. - */ -static void -sp_stroke_style_paint_dragged(SPPaintSelector *psel, SPWidget *spw) -{ - if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { - return; - } - - switch (psel->mode) { - case SP_PAINT_SELECTOR_MODE_COLOR_RGB: - case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: - { - sp_paint_selector_set_flat_color (psel, SP_ACTIVE_DESKTOP, "stroke", "stroke-opacity"); - sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE, - _("Set stroke color")); - break; - } - - default: - g_warning( "file %s: line %d: Paint %d should not emit 'dragged'", - __FILE__, __LINE__, psel->mode); - break; - } -} - -/** - * When the stroke style's paint settings change, this handler updates the - * repr's stroke css style and applies the style to relevant drawing items. - */ -static void -sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw) -{ - if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { - return; - } - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - SPDocument *document = sp_desktop_document (desktop); - Inkscape::Selection *selection = sp_desktop_selection (desktop); - - GSList const *items = selection->itemList(); - - switch (psel->mode) { - case SP_PAINT_SELECTOR_MODE_EMPTY: - // This should not happen. - g_warning ( "file %s: line %d: Paint %d should not emit 'changed'", - __FILE__, __LINE__, psel->mode); - break; - case SP_PAINT_SELECTOR_MODE_MULTIPLE: - // This happens when you switch multiple objects with different gradients to flat color; - // nothing to do here. - break; - - case SP_PAINT_SELECTOR_MODE_NONE: - { - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property(css, "stroke", "none"); - - sp_desktop_set_style (desktop, css); - - sp_repr_css_attr_unref(css); - - sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, - _("Remove stroke")); - break; - } - - case SP_PAINT_SELECTOR_MODE_COLOR_RGB: - case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: - { - sp_paint_selector_set_flat_color (psel, desktop, "stroke", "stroke-opacity"); - sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE, - _("Set stroke color")); - - // on release, toggle undo_label so that the next drag will not be lumped with this one - if (undo_label == undo_label_1) - undo_label = undo_label_2; - else - undo_label = undo_label_1; - - break; - } - - case SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR: - case SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL: - if (items) { - SPGradientType const gradient_type = ( psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR - ? SP_GRADIENT_TYPE_LINEAR - : SP_GRADIENT_TYPE_RADIAL ); - SPGradient *vector = sp_paint_selector_get_gradient_vector(psel); - if (!vector) { - /* No vector in paint selector should mean that we just changed mode */ - - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result = objects_query_fillstroke ((GSList *) items, query, false); - guint32 common_rgb = 0; - if (result == QUERY_STYLE_MULTIPLE_SAME) { - if (!query->fill.isColor()) { - common_rgb = sp_desktop_get_color(desktop, false); - } else { - common_rgb = query->stroke.value.color.toRGBA32( 0xff ); - } - vector = sp_document_default_gradient_vector(document, common_rgb); - } - sp_style_unref(query); - - for (GSList const *i = items; i != NULL; i = i->next) { - if (!vector) { - sp_item_set_gradient(SP_ITEM(i->data), - sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), false), - gradient_type, false); - } else { - sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, false); - } - } - } else { - vector = sp_gradient_ensure_vector_normalized(vector); - for (GSList const *i = items; i != NULL; i = i->next) { - SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, false); - sp_gradient_selector_attrs_to_gradient(gr, psel); - } - } - - sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, - _("Set gradient on stroke")); - } - break; - - case SP_PAINT_SELECTOR_MODE_PATTERN: - - if (items) { - - SPPattern *pattern = sp_paint_selector_get_pattern (psel); - if (!pattern) { - - /* No Pattern in paint selector should mean that we just - * changed mode - dont do jack. - */ - - } else { - Inkscape::XML::Node *patrepr = SP_OBJECT_REPR(pattern); - SPCSSAttr *css = sp_repr_css_attr_new (); - gchar *urltext = g_strdup_printf ("url(#%s)", patrepr->attribute("id")); - sp_repr_css_set_property (css, "stroke", urltext); - - for (GSList const *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *selrepr = SP_OBJECT_REPR (i->data); - SPObject *selobj = SP_OBJECT (i->data); - if (!selrepr) - continue; - - SPStyle *style = SP_OBJECT_STYLE (selobj); - if (style && style->stroke.isPaintserver()) { - SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (selobj); - if (SP_IS_PATTERN (server) && pattern_getroot (SP_PATTERN(server)) == pattern) - // only if this object's pattern is not rooted in our selected pattern, apply - continue; - } - - sp_repr_css_change_recursive (selrepr, css, "style"); - } - - sp_repr_css_attr_unref (css); - g_free (urltext); - - } // end if - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Set pattern on stroke")); - } // end if - - break; - - case SP_PAINT_SELECTOR_MODE_UNSET: - if (items) { - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_unset_property (css, "stroke"); - sp_repr_css_unset_property (css, "stroke-opacity"); - sp_repr_css_unset_property (css, "stroke-width"); - sp_repr_css_unset_property (css, "stroke-miterlimit"); - sp_repr_css_unset_property (css, "stroke-linejoin"); - sp_repr_css_unset_property (css, "stroke-linecap"); - sp_repr_css_unset_property (css, "stroke-dashoffset"); - sp_repr_css_unset_property (css, "stroke-dasharray"); - - sp_desktop_set_style (desktop, css); - sp_repr_css_attr_unref (css); - - sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, - _("Unset stroke")); - } - break; - - default: - g_warning( "file %s: line %d: Paint selector should not be in " - "mode %d", - __FILE__, __LINE__, - psel->mode ); - break; - } - - g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); -} - - - - - -/* Line */ - -static void sp_stroke_style_line_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data); -static void sp_stroke_style_line_selection_changed(SPWidget *spw, Inkscape::Selection *selection, gpointer data); - -static void sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel); - -static void sp_stroke_style_set_join_buttons(Gtk::Container *spw, Gtk::ToggleButton *active); - -static void sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active); - -static void sp_stroke_style_width_changed(Gtk::Container *spw); -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); - - -/** - * Helper function for creating radio buttons. This should probably be re-thought out - * when reimplementing this with Gtkmm. - */ -static Gtk::RadioButton * -sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, - Gtk::HBox *hb, Gtk::Container *spw, - gchar const *key, gchar const *data) -{ - g_assert(icon != NULL); - g_assert(hb != NULL); - g_assert(spw != NULL); - - if (tb == NULL) { - tb = new Gtk::RadioButton(); - } else { - Gtk::RadioButtonGroup grp = tb->get_group(); - tb = new Gtk::RadioButton(grp); - } - - tb->show(); - tb->set_mode(false); - hb->pack_start(*tb, false, false, 0); - spw->set_data(icon, tb); - tb->set_data(key, (gpointer*)data); - tb->signal_toggled().connect(sigc::bind<Gtk::RadioButton *, Gtk::Container *>( - sigc::ptr_fun(&sp_stroke_style_any_toggled), tb, spw)); - Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon))); - g_assert(px != NULL); - px->show(); - tb->add(*px); - - return tb; - -} - -static void -sp_stroke_style_widget_transientize_callback(Inkscape::Application */*inkscape*/, - SPDesktop */*desktop*/, - SPWidget */*spw*/ ) -{ -// TODO: Either of these will cause crashes sometimes -// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); -// ink_markers_menu_update(spw); -} - -/** - * Creates a 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, NRArena const */*arena*/, unsigned /*visionkey*/, NRArenaItem *root) -{ - // 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 = sp_document_repr_doc(sandbox); - Inkscape::XML::Node *mrepr = SP_OBJECT_REPR (marker)->duplicate(xml_doc); - mrepr->setAttribute("id", "sample"); - - // Replace the old sample in the sandbox by the new one - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (sandbox->getObjectById("defs")); - 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 (sp_document_repr_doc (sandbox), 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); - sp_document_root (sandbox)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - sp_document_ensure_up_to_date(sandbox); - - if (object == NULL || !SP_IS_ITEM(object)) - return NULL; // sandbox broken? - - // Find object's bbox in document - Geom::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object))); - Geom::OptRect dbox = SP_ITEM(object)->getBounds(i2doc); - - 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->uri, 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(root, 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 = (SPDefs *) SP_DOCUMENT_DEFS (source); - for ( SPObject *child = sp_object_first_child(SP_OBJECT(defs)); - child != NULL; - child = SP_OBJECT_NEXT (child) ) - { - 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: - NRArena const *arena = NRArena::create(); - unsigned const visionkey = sp_item_display_key_new(1); - NRArenaItem *root = sp_item_invoke_show(SP_ITEM(SP_DOCUMENT_ROOT (sandbox)), (NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); - - for (; marker_list != NULL; marker_list = marker_list->next) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) marker_list->data); - 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, arena, visionkey, root); - 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); - } - - sp_item_invoke_hide(SP_ITEM(sp_document_root(sandbox)), visionkey); - nr_object_unref((NRObject *) arena); -} - -/** - * sp_marker_list_from_doc() - * - * \brief 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 sp_document_new_from_mem (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 = sp_document_new(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) { - sp_document_ensure_up_to_date(doc); - 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 - * items in the current desktop. - */ -static void -sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const which) -{ - if (spw->get_data("update")) { - return; - } - - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *document = sp_desktop_document(desktop); - if (!document) { - return; - } - - /* 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 = SP_OBJECT_REPR(mark); - marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); - } - } else { - marker = markid; - } - 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); - - // Also update the marker dropdown menus, so the document's markers - // show up at the top of the menu -// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); - ink_markers_menu_update(spw, which); - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = (SPItem *) items->data; - if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) // can't set marker to rect, until it's converted to using <path> - continue; - Inkscape::XML::Node *selrepr = SP_OBJECT_REPR((SPItem *) items->data); - if (selrepr) { - sp_repr_css_change_recursive(selrepr, css, "style"); - } - SP_OBJECT(items->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); - SP_OBJECT(items->data)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - } - - sp_repr_css_attr_unref(css); - - sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, - _("Set markers")); - -}; - -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; - - // 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(); - 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(); - 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(); - break; - default: - g_assert_not_reached(); - } -} - -/** - * Sets the stroke width units for all selected items. - * Also handles absolute and dimensionless units. - */ -static gboolean stroke_width_set_unit(SPUnitSelector *, - SPUnit const *old, - SPUnit const *new_units, - Gtk::Container *spw) -{ - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - if (!desktop) { - return FALSE; - } - - Inkscape::Selection *selection = sp_desktop_selection (desktop); - - if (selection->isEmpty()) - return FALSE; - - GSList const *objects = selection->itemList(); - - if ((old->base == SP_UNIT_ABSOLUTE || old->base == SP_UNIT_DEVICE) && - (new_units->base == SP_UNIT_DIMENSIONLESS)) { - - /* Absolute to percentage */ - spw->set_data ("update", GUINT_TO_POINTER (TRUE)); - - Gtk::Adjustment *a = static_cast<Gtk::Adjustment *>(spw->get_data("width")); - float w = sp_units_get_pixels (a->get_value(), *old); - - gdouble average = stroke_average_width (objects); - - if (average == NR_HUGE || average == 0) - return FALSE; - - a->set_value (100.0 * w / average); - - spw->set_data ("update", GUINT_TO_POINTER (FALSE)); - return TRUE; - - } else if ((old->base == SP_UNIT_DIMENSIONLESS) && - (new_units->base == SP_UNIT_ABSOLUTE || new_units->base == SP_UNIT_DEVICE)) { - - /* Percentage to absolute */ - spw->set_data ("update", GUINT_TO_POINTER (TRUE)); - - Gtk::Adjustment *a = static_cast<Gtk::Adjustment *>(spw->get_data ("width")); - - gdouble average = stroke_average_width (objects); - - a->set_value (sp_pixels_get_units (0.01 * a->get_value() * average, *new_units)); - - spw->set_data ("update", GUINT_TO_POINTER (FALSE)); - return TRUE; - } - - return FALSE; -} - - -/** - * \brief Creates a new widget for the line stroke style. - * - */ -Gtk::Container * -sp_stroke_style_line_widget_new(void) -{ - Gtk::Widget *us; - SPDashSelector *ds; - GtkWidget *us_old, *spw_old; - Gtk::Container *spw; - Gtk::Table *t; - Gtk::Adjustment *a; - Gtk::SpinButton *sb; - Gtk::RadioButton *tb; - Gtk::HBox *f, *hb; - - Gtk::Tooltips *tt = new Gtk::Tooltips(); - - spw_old = sp_widget_new_global(INKSCAPE); - spw = dynamic_cast<Gtk::Container *>(manage(Glib::wrap(spw_old))); - - f = new Gtk::HBox(false, 0); - f->show(); - spw->add(*f); - - t = new Gtk::Table(3, 6, false); - t->show(); - t->set_border_width(4); - t->set_row_spacings(4); - f->add(*t); - spw->set_data("stroke", t); - - gint i = 0; - - /* Stroke width */ - spw_label(t, Q_("StrokeWidth|Width:"), 0, i); - - hb = spw_hbox(t, 3, 1, i); - -// 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 -// 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. - - a = new Gtk::Adjustment(1.0, 0.0, 1000.0, 0.1, 10.0, 10.0); - spw->set_data("width", a); - sb = new Gtk::SpinButton(*a, 0.1, 3); - tt->set_tip(*sb, _("Stroke width")); - sb->show(); - - sp_dialog_defocus_on_enter_cpp(sb); - - hb->pack_start(*sb, false, false, 0); - us_old = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); - us = manage(Glib::wrap(us_old)); - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (desktop) - sp_unit_selector_set_unit (SP_UNIT_SELECTOR(us_old), sp_desktop_namedview(desktop)->doc_units); - sp_unit_selector_add_unit(SP_UNIT_SELECTOR(us_old), &sp_unit_get_by_id(SP_UNIT_PERCENT), 0); - g_signal_connect ( G_OBJECT (us_old), "set_unit", G_CALLBACK (stroke_width_set_unit), spw ); - us->show(); - sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us_old), GTK_ADJUSTMENT(a->gobj()) ); - hb->pack_start(*us, FALSE, FALSE, 0); - spw->set_data("units", us_old); - - a->signal_value_changed().connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_width_changed), spw)); - i++; - - /* Join type */ - // TRANSLATORS: The line join style specifies the shape to be used at the - // corners of paths. It can be "miter", "round" or "bevel". - spw_label(t, _("Join:"), 0, i); - - hb = spw_hbox(t, 3, 1, i); - - tb = NULL; - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_MITER, - hb, spw, "join", "miter"); - - // TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner. - // For an example, draw a triangle with a large stroke width and modify the - // "Join" option (in the Fill and Stroke dialog). - tt->set_tip(*tb, _("Miter join")); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_ROUND, - hb, spw, "join", "round"); - - // TRANSLATORS: Round join: joining lines with a rounded corner. - // For an example, draw a triangle with a large stroke width and modify the - // "Join" option (in the Fill and Stroke dialog). - tt->set_tip(*tb, _("Round join")); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_BEVEL, - hb, spw, "join", "bevel"); - - // TRANSLATORS: Bevel join: joining lines with a blunted (flattened) corner. - // For an example, draw a triangle with a large stroke width and modify the - // "Join" option (in the Fill and Stroke dialog). - tt->set_tip(*tb, _("Bevel join")); - - i++; - - /* Miterlimit */ - // TRANSLATORS: Miter limit: only for "miter join", this limits the length - // of the sharp "spike" when the lines connect at too sharp an angle. - // When two line segments meet at a sharp angle, a miter join results in a - // spike that extends well beyond the connection point. The purpose of the - // miter limit is to cut off such spikes (i.e. convert them into bevels) - // when they become too long. - spw_label(t, _("Miter limit:"), 0, i); - - hb = spw_hbox(t, 3, 1, i); - - a = new Gtk::Adjustment(4.0, 0.0, 100.0, 0.1, 10.0, 10.0); - spw->set_data("miterlimit", a); - - sb = new Gtk::SpinButton(*a, 0.1, 2); - tt->set_tip(*sb, _("Maximum length of the miter (in units of stroke width)")); - sb->show(); - spw->set_data("miterlimit_sb", sb); - sp_dialog_defocus_on_enter_cpp(sb); - - hb->pack_start(*sb, false, false, 0); - - a->signal_value_changed().connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_miterlimit_changed), spw)); - i++; - - /* Cap type */ - // TRANSLATORS: cap type specifies the shape for the ends of lines - spw_label(t, _("Cap:"), 0, i); - - hb = spw_hbox(t, 3, 1, i); - - tb = NULL; - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_BUTT, - hb, spw, "cap", "butt"); - - // TRANSLATORS: Butt cap: the line shape does not extend beyond the end point - // of the line; the ends of the line are square - tt->set_tip(*tb, _("Butt cap")); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_ROUND, - hb, spw, "cap", "round"); - - // TRANSLATORS: Round cap: the line shape extends beyond the end point of the - // line; the ends of the line are rounded - tt->set_tip(*tb, _("Round cap")); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_SQUARE, - hb, spw, "cap", "square"); - - // TRANSLATORS: Square cap: the line shape extends beyond the end point of the - // line; the ends of the line are square - tt->set_tip(*tb, _("Square cap")); - - i++; - - - /* Dash */ - spw_label(t, _("Dashes:"), 0, i); - ds = manage(new SPDashSelector); - - ds->show(); - t->attach(*ds, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("dash", ds); - ds->changed_signal.connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_line_dash_changed), spw)); - 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); - tt->set_tip(*marker_start_menu, _("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); - - i++; - spw_label(t, _("Mid Markers:"), 0, i); - marker_mid_menu = ink_marker_menu(spw ,"marker-mid", sandbox); - tt->set_tip(*marker_mid_menu, _("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); - - i++; - spw_label(t, _("End Markers:"), 0, i); - marker_end_menu = ink_marker_menu(spw ,"marker-end", sandbox); - tt->set_tip(*marker_end_menu, _("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); - - i++; - - // FIXME: we cheat and still use gtk+ signals - - gtk_signal_connect(GTK_OBJECT(spw_old), "modify_selection", - GTK_SIGNAL_FUNC(sp_stroke_style_line_selection_modified), - spw); - gtk_signal_connect(GTK_OBJECT(spw_old), "change_selection", - GTK_SIGNAL_FUNC(sp_stroke_style_line_selection_changed), - spw); - - sp_stroke_style_line_update(spw, desktop ? sp_desktop_selection(desktop) : NULL); - - return spw; -} - -/** - * Callback for when stroke style widget is modified. - * Triggers update action. - */ -static void -sp_stroke_style_line_selection_modified(SPWidget *, - Inkscape::Selection *selection, - guint flags, - gpointer data) -{ - Gtk::Container *spw = static_cast<Gtk::Container *>(data); - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { - sp_stroke_style_line_update(spw, selection); - } - -} - -/** - * Callback for when stroke style widget is changed. - * Triggers update action. - */ -static void -sp_stroke_style_line_selection_changed(SPWidget *, - Inkscape::Selection *selection, - gpointer data) -{ - Gtk::Container *spw = static_cast<Gtk::Container *>(data); - sp_stroke_style_line_update(spw, selection); -} - -/** - * Sets selector widgets' dash style from an SPStyle object. - */ -static void -sp_dash_selector_set_from_style(SPDashSelector *dsel, SPStyle *style) -{ - if (style->stroke_dash.n_dash > 0) { - double d[64]; - int len = MIN(style->stroke_dash.n_dash, 64); - for (int i = 0; i < len; i++) { - if (style->stroke_width.computed != 0) - d[i] = style->stroke_dash.dash[i] / style->stroke_width.computed; - else - d[i] = style->stroke_dash.dash[i]; // is there a better thing to do for stroke_width==0? - } - dsel->set_dash(len, d, style->stroke_width.computed != 0 ? - style->stroke_dash.offset / style->stroke_width.computed : - style->stroke_dash.offset); - } else { - dsel->set_dash(0, NULL, 0.0); - } -} - -/** - * Sets the join type for a line, and updates the stroke style widget's buttons - */ -static void -sp_jointype_set (Gtk::Container *spw, unsigned const jointype) -{ - Gtk::RadioButton *tb = NULL; - switch (jointype) { - case SP_STROKE_LINEJOIN_MITER: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_MITER)); - break; - case SP_STROKE_LINEJOIN_ROUND: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_ROUND)); - break; - case SP_STROKE_LINEJOIN_BEVEL: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_BEVEL)); - break; - default: - break; - } - sp_stroke_style_set_join_buttons(spw, tb); -} - -/** - * Sets the cap type for a line, and updates the stroke style widget's buttons - */ -static void -sp_captype_set (Gtk::Container *spw, unsigned const captype) -{ - Gtk::RadioButton *tb = NULL; - switch (captype) { - case SP_STROKE_LINECAP_BUTT: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_BUTT)); - break; - case SP_STROKE_LINECAP_ROUND: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_ROUND)); - break; - case SP_STROKE_LINECAP_SQUARE: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_SQUARE)); - break; - default: - break; - } - sp_stroke_style_set_cap_buttons(spw, tb); -} - -/** - * Callback for when stroke style widget is updated, including markers, cap type, - * join type, etc. - */ -static void -sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) -{ - if (spw->get_data("update")) { - return; - } - - spw->set_data("update", GINT_TO_POINTER(TRUE)); - - Gtk::Table *sset = static_cast<Gtk::Table *>(spw->get_data("stroke")); - Gtk::Adjustment *width = static_cast<Gtk::Adjustment *>(spw->get_data("width")); - Gtk::Adjustment *ml = static_cast<Gtk::Adjustment *>(spw->get_data("miterlimit")); - SPUnitSelector *us = SP_UNIT_SELECTOR(spw->get_data("units")); - SPDashSelector *dsel = static_cast<SPDashSelector *>(spw->get_data("dash")); - - // create temporary style - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - // query into it - int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEWIDTH); - int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT); - int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKECAP); - int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEJOIN); - - if (result_sw == QUERY_STYLE_NOTHING) { - /* No objects stroked, set insensitive */ - sset->set_sensitive(false); - - spw->set_data("update", GINT_TO_POINTER(FALSE)); - return; - } else { - sset->set_sensitive(true); - - SPUnit const *unit = sp_unit_selector_get_unit(us); - - if (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED) { - sp_unit_selector_set_unit(us, &sp_unit_get_by_id(SP_UNIT_PERCENT)); - } else { - // same width, or only one object; no sense to keep percent, switch to absolute - if (unit->base != SP_UNIT_ABSOLUTE && unit->base != SP_UNIT_DEVICE) { - sp_unit_selector_set_unit(us, sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units); - } - } - - unit = sp_unit_selector_get_unit(us); - - if (unit->base == SP_UNIT_ABSOLUTE || unit->base == SP_UNIT_DEVICE) { - double avgwidth = sp_pixels_get_units (query->stroke_width.computed, *unit); - width->set_value(avgwidth); - } else { - width->set_value(100); - } - } - - if (result_ml != QUERY_STYLE_NOTHING) - ml->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness? - - if (result_join != QUERY_STYLE_MULTIPLE_DIFFERENT) { - sp_jointype_set(spw, query->stroke_linejoin.value); - } else { - sp_stroke_style_set_join_buttons(spw, NULL); - } - - if (result_cap != QUERY_STYLE_MULTIPLE_DIFFERENT) { - sp_captype_set (spw, query->stroke_linecap.value); - } else { - sp_stroke_style_set_cap_buttons(spw, NULL); - } - - sp_style_unref(query); - - if (!sel || sel->isEmpty()) - return; - - GSList const *objects = sel->itemList(); - SPObject * const object = SP_OBJECT(objects->data); - SPStyle * const style = SP_OBJECT_STYLE(object); - - /* Markers */ - sp_stroke_style_update_marker_menus(spw, objects); // FIXME: make this desktop query too - - /* Dash */ - sp_dash_selector_set_from_style(dsel, style); // FIXME: make this desktop query too - - sset->set_sensitive(true); - - spw->set_data("update", GINT_TO_POINTER(FALSE)); -} - -/** - * Sets a line's dash properties in a CSS style object. - */ -static void -sp_stroke_style_set_scaled_dash(SPCSSAttr *css, - int ndash, double *dash, double offset, - double scale) -{ - if (ndash > 0) { - Inkscape::CSSOStringStream osarray; - for (int i = 0; i < ndash; i++) { - osarray << dash[i] * scale; - if (i < (ndash - 1)) { - osarray << ","; - } - } - sp_repr_css_set_property(css, "stroke-dasharray", osarray.str().c_str()); - - Inkscape::CSSOStringStream osoffset; - osoffset << offset * scale; - sp_repr_css_set_property(css, "stroke-dashoffset", osoffset.str().c_str()); - } else { - sp_repr_css_set_property(css, "stroke-dasharray", "none"); - sp_repr_css_set_property(css, "stroke-dashoffset", NULL); - } -} - -/** - * Sets line properties like width, dashes, markers, etc. on all currently selected items. - */ -static void -sp_stroke_style_scale_line(Gtk::Container *spw) -{ - if (spw->get_data("update")) { - return; - } - - spw->set_data("update", GINT_TO_POINTER(TRUE)); - - Gtk::Adjustment *wadj = static_cast<Gtk::Adjustment *>(spw->get_data("width")); - SPUnitSelector *us = SP_UNIT_SELECTOR(spw->get_data("units")); - SPDashSelector *dsel = static_cast<SPDashSelector *>(spw->get_data("dash")); - Gtk::Adjustment *ml = static_cast<Gtk::Adjustment *>(spw->get_data("miterlimit")); - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - SPDocument *document = sp_desktop_document (desktop); - Inkscape::Selection *selection = sp_desktop_selection (desktop); - - GSList const *items = selection->itemList(); - - /* TODO: Create some standardized method */ - SPCSSAttr *css = sp_repr_css_attr_new(); - - if (items) { - - double width_typed = wadj->get_value(); - double const miterlimit = ml->get_value(); - - SPUnit const *const unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us)); - - double *dash, offset; - int ndash; - dsel->get_dash(&ndash, &dash, &offset); - - for (GSList const *i = items; i != NULL; i = i->next) { - /* Set stroke width */ - double width; - if (unit->base == SP_UNIT_ABSOLUTE || unit->base == SP_UNIT_DEVICE) { - width = sp_units_get_pixels (width_typed, *unit); - } else { // percentage - gdouble old_w = SP_OBJECT_STYLE (i->data)->stroke_width.computed; - width = old_w * width_typed / 100; - } - - { - Inkscape::CSSOStringStream os_width; - os_width << width; - sp_repr_css_set_property(css, "stroke-width", os_width.str().c_str()); - } - - { - Inkscape::CSSOStringStream os_ml; - os_ml << miterlimit; - sp_repr_css_set_property(css, "stroke-miterlimit", os_ml.str().c_str()); - } - - /* Set dash */ - sp_stroke_style_set_scaled_dash(css, ndash, dash, offset, width); - - sp_desktop_apply_css_recursive (SP_OBJECT(i->data), css, true); - } - - g_free(dash); - - if (unit->base != SP_UNIT_ABSOLUTE && unit->base != SP_UNIT_DEVICE) { - // reset to 100 percent - wadj->set_value(100.0); - } - - } - - // we have already changed the items, so set style without changing selection - // FIXME: move the above stroke-setting stuff, including percentages, to desktop-style - sp_desktop_set_style (desktop, css, false); - - sp_repr_css_attr_unref(css); - - sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, - _("Set stroke style")); - - spw->set_data("update", GINT_TO_POINTER(FALSE)); -} - -/** - * Callback for when the stroke style's width changes. - * Causes all line styles to be applied to all selected items. - */ -static void -sp_stroke_style_width_changed(Gtk::Container *spw) -{ - if (spw->get_data("update")) { - return; - } - - sp_stroke_style_scale_line(spw); -} - -/** - * Callback for when the stroke style's miterlimit changes. - * Causes all line styles to be applied to all selected items. - */ -static void -sp_stroke_style_miterlimit_changed(Gtk::Container *spw) -{ - if (spw->get_data("update")) { - return; - } - - sp_stroke_style_scale_line(spw); -} - -/** - * Callback for when the stroke style's dash changes. - * Causes all line styles to be applied to all selected items. - */ - -static void -sp_stroke_style_line_dash_changed(Gtk::Container *spw) -{ - if (spw->get_data("update")) { - return; - } - - sp_stroke_style_scale_line(spw); -} - -/** - * \brief This routine handles toggle events for buttons in the stroke style - * dialog. - * When activated, this routine gets the data for the various widgets, and then - * calls the respective routines to update css properties, etc. - * - */ -static void -sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *spw) -{ - if (spw->get_data("update")) { - return; - } - - if (tb->get_active()) { - - gchar const *join - = static_cast<gchar const *>(tb->get_data("join")); - gchar const *cap - = static_cast<gchar const *>(tb->get_data("cap")); - - if (join) { - Gtk::SpinButton *ml = static_cast<Gtk::SpinButton *>(spw->get_data("miterlimit_sb")); - ml->set_sensitive(!strcmp(join, "miter")); - } - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - /* TODO: Create some standardized method */ - SPCSSAttr *css = sp_repr_css_attr_new(); - - if (join) { - sp_repr_css_set_property(css, "stroke-linejoin", join); - - sp_desktop_set_style (desktop, css); - - sp_stroke_style_set_join_buttons(spw, tb); - } else if (cap) { - sp_repr_css_set_property(css, "stroke-linecap", cap); - - sp_desktop_set_style (desktop, css); - - sp_stroke_style_set_cap_buttons(spw, tb); - } - - sp_repr_css_attr_unref(css); - - sp_document_done(sp_desktop_document(desktop), SP_VERB_DIALOG_FILL_STROKE, - _("Set stroke style")); - } -} - -/** - * Updates the join style toggle buttons - */ -static void -sp_stroke_style_set_join_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) -{ - Gtk::RadioButton *tb; - - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_MITER)); - tb->set_active(active == tb); - - Gtk::SpinButton *ml = static_cast<Gtk::SpinButton *>(spw->get_data("miterlimit_sb")); - ml->set_sensitive(active == tb); - - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_ROUND)); - tb->set_active(active == tb); - - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_BEVEL)); - tb->set_active(active == tb); -} - -/** - * Updates the cap style toggle buttons - */ -static void -sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) -{ - Gtk::RadioButton *tb; - - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_BUTT)); - tb->set_active(active == tb); - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_ROUND)); - tb->set_active(active == tb); - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_SQUARE)); - 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 (SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")) - mark_is_stock = true; - - gchar *markname; - if (mark_is_stock) - markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")); - else - markname = g_strdup(SP_OBJECT_REPR(marker)->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 - * that marker. - */ -static void -sp_stroke_style_update_marker_menus(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 } - }; - - bool all_texts = true; - for (GSList *i = (GSList *) objects; i != NULL; i = i->next) { - if (!SP_IS_TEXT (i->data)) { - all_texts = false; - } - } - - 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); - } - - // We show markers of the first object in the list only - // FIXME: use the first in the list that has the marker of each type, if any - SPObject *object = SP_OBJECT(objects->data); - - 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)); - - // Quit if we're in update state - if (mnu->get_data("update")) { - return; - } - - if (object->style->marker[keyloc[i].loc].value != NULL && !all_texts) { - // If the object has this type of markers, - - // Extract the name of the marker that the object uses - SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, SP_OBJECT_DOCUMENT(object)); - // Scroll the menu to that marker - ink_marker_menu_set_current(marker, mnu); - - } else { - mnu->set_history(0); - } - } -} - - -/** - * Extract the actual name of the link - * e.g. get mTriangle from url(#mTriangle). - * \return Buffer containing the actual name, allocated from GLib; - * the caller should free the buffer when they no longer need it. - */ -static SPObject* -ink_extract_marker_name(gchar const *n, SPDocument *doc) -{ - gchar const *p = n; - while (*p != '\0' && *p != '#') { - p++; - } - - if (*p == '\0' || p[1] == '\0') { - return NULL; - } - - p++; - int c = 0; - while (p[c] != '\0' && p[c] != ')') { - c++; - } - - if (p[c] == '\0') { - return NULL; - } - - gchar* b = g_strdup(p); - b[c] = '\0'; - - // FIXME: get the document from the object and let the caller pass it in - SPObject *marker = doc->getObjectById(b); - return marker; -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/stroke-style.h b/src/dialogs/stroke-style.h deleted file mode 100644 index b947209e3..000000000 --- a/src/dialogs/stroke-style.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * @brief Stroke style dialog - */ -/* Author: - * Lauris Kaplinski <lauris@ximian.com> - * - * Copyright (C) 2001 Ximian, Inc. - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DIALOGS_STROKE_STYLE_H -#define SEEN_DIALOGS_STROKE_STYLE_H - -#include <glib.h> - -#include <gtk/gtkwidget.h> - -#include "forward.h" -#include "display/canvas-bpath.h" - -GtkWidget *sp_stroke_style_paint_widget_new (void); -Gtk::Container *sp_stroke_style_line_widget_new (void); - -#endif - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/swatches.cpp b/src/dialogs/swatches.cpp deleted file mode 100644 index 4546efe13..000000000 --- a/src/dialogs/swatches.cpp +++ /dev/null @@ -1,1213 +0,0 @@ -/** @file - * @brief Color swatches dialog - */ -/* Authors: - * Jon A. Cruz - * John Bintz - * - * Copyright (C) 2005 Jon A. Cruz - * Copyright (C) 2008 John Bintz - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <errno.h> - -#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types -#include <gtk/gtkdnd.h> -#include <gtk/gtkmenu.h> -#include <gtk/gtkmenuitem.h> -#include <gtk/gtkseparatormenuitem.h> - -#include <glibmm/i18n.h> -#include <gdkmm/pixbuf.h> -#include "inkscape.h" -#include "desktop.h" -#include "message-context.h" -#include "document.h" -#include "desktop-handles.h" -#include "extension/db.h" -#include "inkscape.h" -#include "svg/svg-color.h" -#include "desktop-style.h" -#include "io/sys.h" -#include "path-prefix.h" -#include "swatches.h" -#include "sp-item.h" -#include "preferences.h" - -#include "eek-preview.h" - -namespace Inkscape { -namespace UI { -namespace Dialogs { - -ColorItem::ColorItem() : _isRemove(true){}; -ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) : - def( r, g, b, name ), - _isRemove(false), - _isLive(false), - _linkIsTone(false), - _linkPercent(0), - _linkGray(0), - _linkSrc(0) -{ -} - -ColorItem::~ColorItem() -{ -} - -ColorItem::ColorItem(ColorItem const &other) : - Inkscape::UI::Previewable() -{ - if ( this != &other ) { - *this = other; - } -} - -ColorItem &ColorItem::operator=(ColorItem const &other) -{ - if ( this != &other ) { - def = other.def; - - // TODO - correct linkage - _linkSrc = other._linkSrc; - g_message("Erk!"); - } - return *this; -} - - -class JustForNow -{ -public: - JustForNow() : _prefWidth(0) {} - - Glib::ustring _name; - int _prefWidth; - std::vector<ColorItem*> _colors; -}; - -static std::vector<JustForNow*> possible; - - - -typedef enum { - APP_X_INKY_COLOR_ID = 0, - APP_X_INKY_COLOR = 0, - APP_X_COLOR, - TEXT_DATA -} colorFlavorType; - -//TODO: warning: deprecated conversion from string constant to ‘gchar*’ -// -//Turn out to be warnings that we should probably leave in place. The -// pointers/types used need to be read-only. So until we correct the using -// code, those warnings are actually desired. They say "Hey! Fix this". We -// definitely don't want to hide/ignore them. --JonCruz -static const GtkTargetEntry sourceColorEntries[] = { -#if ENABLE_MAGIC_COLORS -// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, - {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, -#endif // ENABLE_MAGIC_COLORS - {"application/x-color", 0, APP_X_COLOR}, - {"text/plain", 0, TEXT_DATA}, -}; - -void ColorItem::_dragGetColorData( GtkWidget *widget, - GdkDragContext *drag_context, - GtkSelectionData *data, - guint info, - guint time, - gpointer user_data) -{ - (void)widget; - (void)drag_context; - (void)time; - static GdkAtom typeXColor = gdk_atom_intern("application/x-color", FALSE); - static GdkAtom typeText = gdk_atom_intern("text/plain", FALSE); - - ColorItem* item = reinterpret_cast<ColorItem*>(user_data); - if ( info == TEXT_DATA ) { - gchar* tmp = g_strdup_printf("#%02x%02x%02x", item->def.getR(), item->def.getG(), item->def.getB() ); - - gtk_selection_data_set( data, - typeText, - 8, // format - (guchar*)tmp, - strlen((const char*)tmp) + 1); - g_free(tmp); - tmp = 0; - } else if ( info == APP_X_INKY_COLOR ) { - Glib::ustring paletteName; - - // Find where this thing came from - bool found = false; - int index = 0; - for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end() && !found; ++it ) { - JustForNow* curr = *it; - index = 0; - for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { - if ( item == *zz ) { - found = true; - paletteName = curr->_name; - break; - } else { - index++; - } - } - } - -// if ( found ) { -// g_message("Found the color at entry %d in palette '%s'", index, paletteName.c_str() ); -// } else { -// g_message("Unable to find the color"); -// } - int itemCount = 4 + 2 + 1 + paletteName.length(); - - guint16* tmp = new guint16[itemCount]; - tmp[0] = (item->def.getR() << 8) | item->def.getR(); - tmp[1] = (item->def.getG() << 8) | item->def.getG(); - tmp[2] = (item->def.getB() << 8) | item->def.getB(); - tmp[3] = 0xffff; - tmp[4] = (item->_isLive || !item->_listeners.empty() || (item->_linkSrc != 0) ) ? 1 : 0; - - tmp[5] = index; - tmp[6] = paletteName.length(); - for ( unsigned int i = 0; i < paletteName.length(); i++ ) { - tmp[7 + i] = paletteName[i]; - } - gtk_selection_data_set( data, - typeXColor, - 16, // format - reinterpret_cast<const guchar*>(tmp), - itemCount * 2); - delete[] tmp; - } else { - guint16 tmp[4]; - tmp[0] = (item->def.getR() << 8) | item->def.getR(); - tmp[1] = (item->def.getG() << 8) | item->def.getG(); - tmp[2] = (item->def.getB() << 8) | item->def.getB(); - tmp[3] = 0xffff; - gtk_selection_data_set( data, - typeXColor, - 16, // format - reinterpret_cast<const guchar*>(tmp), - (3+1) * 2); - } -} - -static void dragBegin( GtkWidget *widget, GdkDragContext* dc, gpointer data ) -{ - (void)widget; - ColorItem* item = reinterpret_cast<ColorItem*>(data); - if ( item ) - { - if (item->isRemove()){ - GError *error = NULL; - gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); - gsize bytesRead = 0; - gsize bytesWritten = 0; - gchar *localFilename = g_filename_from_utf8( filepath, - -1, - &bytesRead, - &bytesWritten, - &error); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(localFilename, 32, 24, FALSE, &error); - g_free(localFilename); - g_free(filepath); - gtk_drag_set_icon_pixbuf( dc, pixbuf, 0, 0 ); - return; - } - - Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, 32, 24 ); - guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) - | (0x00ff0000 & (item->def.getG() << 16)) - | (0x0000ff00 & (item->def.getB() << 8)); - thumb->fill( fillWith ); - gtk_drag_set_icon_pixbuf( dc, thumb->gobj(), 0, 0 ); - } - -} - -//"drag-drop" -// gboolean dragDropColorData( GtkWidget *widget, -// GdkDragContext *drag_context, -// gint x, -// gint y, -// guint time, -// gpointer user_data) -// { -// // TODO finish - -// return TRUE; -// } - -static void handleClick( GtkWidget* widget, gpointer callback_data ) { - (void)widget; - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - item->buttonClicked(false); - } -} - -static void handleSecondaryClick( GtkWidget* widget, gint arg1, gpointer callback_data ) { - (void)widget; - (void)arg1; - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - item->buttonClicked(true); - } -} - -static gboolean handleEnterNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if ( desktop ) { - gchar* msg = g_strdup_printf(_("Color: <b>%s</b>; <b>Click</b> to set fill, <b>Shift+click</b> to set stroke"), - item->def.descr.c_str()); - desktop->tipsMessageContext()->set(Inkscape::INFORMATION_MESSAGE, msg); - g_free(msg); - } - } - return FALSE; -} - -static gboolean handleLeaveNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if ( desktop ) { - desktop->tipsMessageContext()->clear(); - } - } - return FALSE; -} - -static GtkWidget* popupMenu = 0; -static ColorItem* bounceTarget = 0; - -static void redirClick( GtkMenuItem *menuitem, gpointer user_data ) -{ - (void)user_data; - if ( bounceTarget ) { - handleClick( GTK_WIDGET(menuitem), bounceTarget ); - } -} - -static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer user_data ) -{ - (void)user_data; - if ( bounceTarget ) { - handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget ); - } -} - -static gboolean handleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data) -{ - (void)widget; - gboolean handled = FALSE; - - if ( (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) { - if ( !popupMenu ) { - popupMenu = gtk_menu_new(); - GtkWidget* child = 0; - - //TRANSLATORS: An item in context menu on a colour in the swatches - child = gtk_menu_item_new_with_label(_("Set fill")); - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(redirClick), - user_data); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - - //TRANSLATORS: An item in context menu on a colour in the swatches - child = gtk_menu_item_new_with_label(_("Set stroke")); - - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(redirSecondaryClick), - user_data); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - - gtk_widget_show_all(popupMenu); - } - - ColorItem* item = reinterpret_cast<ColorItem*>(user_data); - if ( item ) { - bounceTarget = item; - if ( popupMenu ) { - gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time); - handled = TRUE; - } - } - } - - return handled; -} - -static void dieDieDie( GtkObject *obj, gpointer user_data ) -{ - g_message("die die die %p %p", obj, user_data ); -} - -//TODO: warning: deprecated conversion from string constant to ‘gchar*’ -// -//Turn out to be warnings that we should probably leave in place. The -// pointers/types used need to be read-only. So until we correct the using -// code, those warnings are actually desired. They say "Hey! Fix this". We -// definitely don't want to hide/ignore them. --JonCruz -static const GtkTargetEntry destColorTargets[] = { -#if ENABLE_MAGIC_COLORS -// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, - {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, -#endif // ENABLE_MAGIC_COLORS - {"application/x-color", 0, APP_X_COLOR}, -}; - -#include "color.h" // for SP_RGBA32_U_COMPOSE - -void ColorItem::_dropDataIn( GtkWidget *widget, - GdkDragContext *drag_context, - gint x, gint y, - GtkSelectionData *data, - guint info, - guint event_time, - gpointer user_data) -{ - (void)widget; - (void)drag_context; - (void)x; - (void)y; - (void)event_time; -// g_message(" droppy droppy %d", info); - switch (info) { - case APP_X_INKY_COLOR: - { - if ( data->length >= 8 ) { - // Careful about endian issues. - guint16* dataVals = (guint16*)data->data; - if ( user_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(user_data); - if ( item->def.isEditable() ) { - // Shove on in the new value - item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); - } - } - } - break; - } - case APP_X_COLOR: - { - if ( data->length == 8 ) { - // Careful about endian issues. - guint16* dataVals = (guint16*)data->data; -// { -// gchar c[64] = {0}; -// sp_svg_write_color( c, 64, -// SP_RGBA32_U_COMPOSE( -// 0x0ff & (dataVals[0] >> 8), -// 0x0ff & (dataVals[1] >> 8), -// 0x0ff & (dataVals[2] >> 8), -// 0xff // can't have transparency in the color itself -// //0x0ff & (data->data[3] >> 8), -// )); -// } - if ( user_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(user_data); - if ( item->def.isEditable() ) { - // Shove on in the new value - item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); - } - } - } - break; - } - default: - g_message("unknown drop type"); - } - -} - -static bool bruteForce( SPDocument* document, Inkscape::XML::Node* node, Glib::ustring const& match, int r, int g, int b ) -{ - bool changed = false; - - if ( node ) { - gchar const * val = node->attribute("inkscape:x-fill-tag"); - if ( val && (match == val) ) { - SPObject *obj = document->getObjectByRepr( node ); - - gchar c[64] = {0}; - sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, "fill", c ); - - sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); - ((SPItem*)obj)->updateRepr(); - - changed = true; - } - - val = node->attribute("inkscape:x-stroke-tag"); - if ( val && (match == val) ) { - SPObject *obj = document->getObjectByRepr( node ); - - gchar c[64] = {0}; - sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, "stroke", c ); - - sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); - ((SPItem*)obj)->updateRepr(); - - changed = true; - } - - Inkscape::XML::Node* first = node->firstChild(); - changed |= bruteForce( document, first, match, r, g, b ); - - changed |= bruteForce( document, node->next(), match, r, g, b ); - } - - return changed; -} - -void ColorItem::_colorDefChanged(void* data) -{ - ColorItem* item = reinterpret_cast<ColorItem*>(data); - if ( item ) { - for ( std::vector<Gtk::Widget*>::iterator it = item->_previews.begin(); it != item->_previews.end(); ++it ) { - Gtk::Widget* widget = *it; - if ( IS_EEK_PREVIEW(widget->gobj()) ) { - EekPreview * preview = EEK_PREVIEW(widget->gobj()); - eek_preview_set_color( preview, - (item->def.getR() << 8) | item->def.getR(), - (item->def.getG() << 8) | item->def.getG(), - (item->def.getB() << 8) | item->def.getB() ); - - eek_preview_set_linked( preview, (LinkType)((item->_linkSrc ? PREVIEW_LINK_IN:0) - | (item->_listeners.empty() ? 0:PREVIEW_LINK_OUT) - | (item->_isLive ? PREVIEW_LINK_OTHER:0)) ); - - widget->queue_draw(); - } - } - - for ( std::vector<ColorItem*>::iterator it = item->_listeners.begin(); it != item->_listeners.end(); ++it ) { - guint r = item->def.getR(); - guint g = item->def.getG(); - guint b = item->def.getB(); - - if ( (*it)->_linkIsTone ) { - r = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * r) ) / 100; - g = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * g) ) / 100; - b = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * b) ) / 100; - } else { - r = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * r) ) / 100; - g = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * g) ) / 100; - b = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * b) ) / 100; - } - - (*it)->def.setRGB( r, g, b ); - } - - - // Look for objects using this color - { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if ( desktop ) { - SPDocument* document = sp_desktop_document( desktop ); - Inkscape::XML::Node *rroot = sp_document_repr_root( document ); - if ( rroot ) { - - // Find where this thing came from - Glib::ustring paletteName; - bool found = false; - int index = 0; - for ( std::vector<JustForNow*>::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) { - JustForNow* curr = *it2; - index = 0; - for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { - if ( item == *zz ) { - found = true; - paletteName = curr->_name; - break; - } else { - index++; - } - } - } - - if ( !paletteName.empty() ) { - gchar* str = g_strdup_printf("%d|", index); - paletteName.insert( 0, str ); - g_free(str); - str = 0; - - if ( bruteForce( document, rroot, paletteName, item->def.getR(), item->def.getG(), item->def.getB() ) ) { - sp_document_done( document , SP_VERB_DIALOG_SWATCHES, - _("Change color definition")); - } - } - } - } - } - } -} - - -Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, ::PreviewSize size, guint ratio) -{ - Gtk::Widget* widget = 0; - if ( style == PREVIEW_STYLE_BLURB) { - Gtk::Label *lbl = new Gtk::Label(def.descr); - lbl->set_alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER); - widget = lbl; - } else { -// Glib::ustring blank(" "); -// if ( size == Inkscape::ICON_SIZE_MENU || size == Inkscape::ICON_SIZE_DECORATION ) { -// blank = " "; -// } - - GtkWidget* eekWidget = eek_preview_new(); - EekPreview * preview = EEK_PREVIEW(eekWidget); - Gtk::Widget* newBlot = Glib::wrap(eekWidget); - - eek_preview_set_color( preview, (def.getR() << 8) | def.getR(), (def.getG() << 8) | def.getG(), (def.getB() << 8) | def.getB()); - if ( _isRemove ) { - GError *error = NULL; - gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); - gsize bytesRead = 0; - gsize bytesWritten = 0; - gchar *localFilename = g_filename_from_utf8( filepath, - -1, - &bytesRead, - &bytesWritten, - &error); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(localFilename, &error); - if (!pixbuf) { - g_warning("Null pixbuf for %p [%s]", localFilename, localFilename ); - } - g_free(localFilename); - g_free(filepath); - - eek_preview_set_pixbuf( preview, pixbuf ); - } - - eek_preview_set_details( preview, (::PreviewStyle)style, (::ViewType)view, (::PreviewSize)size, ratio ); - eek_preview_set_linked( preview, (LinkType)((_linkSrc ? PREVIEW_LINK_IN:0) - | (_listeners.empty() ? 0:PREVIEW_LINK_OUT) - | (_isLive ? PREVIEW_LINK_OTHER:0)) ); - - def.addCallback( _colorDefChanged, this ); - - GValue val = {0, {{0}, {0}}}; - g_value_init( &val, G_TYPE_BOOLEAN ); - g_value_set_boolean( &val, FALSE ); - g_object_set_property( G_OBJECT(preview), "focus-on-click", &val ); - -/* - Gtk::Button *btn = new Gtk::Button(blank); - Gdk::Color color; - color.set_rgb((_r << 8)|_r, (_g << 8)|_g, (_b << 8)|_b); - btn->modify_bg(Gtk::STATE_NORMAL, color); - btn->modify_bg(Gtk::STATE_ACTIVE, color); - btn->modify_bg(Gtk::STATE_PRELIGHT, color); - btn->modify_bg(Gtk::STATE_SELECTED, color); - - Gtk::Widget* newBlot = btn; -*/ - - tips.set_tip((*newBlot), def.descr); - -/* - newBlot->signal_clicked().connect( sigc::mem_fun(*this, &ColorItem::buttonClicked) ); - - sigc::signal<void> type_signal_something; -*/ - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "clicked", - G_CALLBACK(handleClick), - this); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "alt-clicked", - G_CALLBACK(handleSecondaryClick), - this); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "button-press-event", - G_CALLBACK(handleButtonPress), - this); - - gtk_drag_source_set( GTK_WIDGET(newBlot->gobj()), - GDK_BUTTON1_MASK, - sourceColorEntries, - G_N_ELEMENTS(sourceColorEntries), - GdkDragAction(GDK_ACTION_MOVE | GDK_ACTION_COPY) ); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "drag-data-get", - G_CALLBACK(ColorItem::_dragGetColorData), - this); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "drag-begin", - G_CALLBACK(dragBegin), - this ); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "enter-notify-event", - G_CALLBACK(handleEnterNotify), - this); - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "leave-notify-event", - G_CALLBACK(handleLeaveNotify), - this); - -// g_signal_connect( G_OBJECT(newBlot->gobj()), -// "drag-drop", -// G_CALLBACK(dragDropColorData), -// this); - - if ( def.isEditable() ) - { - gtk_drag_dest_set( GTK_WIDGET(newBlot->gobj()), - GTK_DEST_DEFAULT_ALL, - destColorTargets, - G_N_ELEMENTS(destColorTargets), - GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); - - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "drag-data-received", - G_CALLBACK(_dropDataIn), - this ); - } - - g_signal_connect( G_OBJECT(newBlot->gobj()), - "destroy", - G_CALLBACK(dieDieDie), - this); - - - widget = newBlot; - } - - _previews.push_back( widget ); - - return widget; -} - -void ColorItem::buttonClicked(bool secondary) -{ - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (!desktop) return; - char const * attrName = secondary ? "stroke" : "fill"; - - gchar c[64]; - if (!_isRemove){ - guint32 rgba = (def.getR() << 24) | (def.getG() << 16) | (def.getB() << 8) | 0xff; - sp_svg_write_color(c, sizeof(c), rgba); - } - - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, attrName, _isRemove ? "none" : c ); - sp_desktop_set_style(desktop, css); - sp_repr_css_attr_unref(css); - - if (_isRemove){ - sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, - secondary? _("Remove stroke color") : _("Remove fill color")); - } else { - sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, - secondary? _("Set stroke color from swatch") : _("Set fill color from swatch")); - } -} - -static char* trim( char* str ) { - char* ret = str; - while ( *str && (*str == ' ' || *str == '\t') ) { - str++; - } - ret = str; - while ( *str ) { - str++; - } - str--; - while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) { - *str-- = 0; - } - return ret; -} - -void skipWhitespace( char*& str ) { - while ( *str == ' ' || *str == '\t' ) { - str++; - } -} - -bool parseNum( char*& str, int& val ) { - val = 0; - while ( '0' <= *str && *str <= '9' ) { - val = val * 10 + (*str - '0'); - str++; - } - bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n'); - return retval; -} - - -static bool getBlock( std::string& dst, guchar ch, std::string const str ) -{ - bool good = false; - std::string::size_type pos = str.find(ch); - if ( pos != std::string::npos ) - { - std::string::size_type pos2 = str.find( '(', pos ); - if ( pos2 != std::string::npos ) { - std::string::size_type endPos = str.find( ')', pos2 ); - if ( endPos != std::string::npos ) { - dst = str.substr( pos2 + 1, (endPos - pos2 - 1) ); - good = true; - } - } - } - return good; -} - -static bool popVal( guint64& numVal, std::string& str ) -{ - bool good = false; - std::string::size_type endPos = str.find(','); - if ( endPos == std::string::npos ) { - endPos = str.length(); - } - - if ( endPos != std::string::npos && endPos > 0 ) { - std::string xxx = str.substr( 0, endPos ); - const gchar* ptr = xxx.c_str(); - gchar* endPtr = 0; - numVal = g_ascii_strtoull( ptr, &endPtr, 10 ); - if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { - // overflow - } else if ( (numVal == 0) && (endPtr == ptr) ) { - // failed conversion - } else { - good = true; - str.erase( 0, endPos + 1 ); - } - } - - return good; -} - -void ColorItem::_wireMagicColors( void* p ) -{ - JustForNow* onceMore = reinterpret_cast<JustForNow*>(p); - if ( onceMore ) - { - for ( std::vector<ColorItem*>::iterator it = onceMore->_colors.begin(); it != onceMore->_colors.end(); ++it ) - { - std::string::size_type pos = (*it)->def.descr.find("*{"); - if ( pos != std::string::npos ) - { - std::string subby = (*it)->def.descr.substr( pos + 2 ); - std::string::size_type endPos = subby.find("}*"); - if ( endPos != std::string::npos ) - { - subby.erase( endPos ); - //g_message("FOUND MAGIC at '%s'", (*it)->def.descr.c_str()); - //g_message(" '%s'", subby.c_str()); - - if ( subby.find('E') != std::string::npos ) - { - (*it)->def.setEditable( true ); - } - - if ( subby.find('L') != std::string::npos ) - { - (*it)->_isLive = true; - } - - std::string part; - // Tint. index + 1 more val. - if ( getBlock( part, 'T', subby ) ) { - guint64 colorIndex = 0; - if ( popVal( colorIndex, part ) ) { - guint64 percent = 0; - if ( popVal( percent, part ) ) { - (*it)->_linkTint( *(onceMore->_colors[colorIndex]), percent ); - } - } - } - - // Shade/tone. index + 1 or 2 more val. - if ( getBlock( part, 'S', subby ) ) { - guint64 colorIndex = 0; - if ( popVal( colorIndex, part ) ) { - guint64 percent = 0; - if ( popVal( percent, part ) ) { - guint64 grayLevel = 0; - if ( !popVal( grayLevel, part ) ) { - grayLevel = 0; - } - (*it)->_linkTone( *(onceMore->_colors[colorIndex]), percent, grayLevel ); - } - } - } - - } - } - } - } -} - - -void ColorItem::_linkTint( ColorItem& other, int percent ) -{ - if ( !_linkSrc ) - { - other._listeners.push_back(this); - _linkIsTone = false; - _linkPercent = percent; - if ( _linkPercent > 100 ) - _linkPercent = 100; - if ( _linkPercent < 0 ) - _linkPercent = 0; - _linkGray = 0; - _linkSrc = &other; - - ColorItem::_colorDefChanged(&other); - } -} - -void ColorItem::_linkTone( ColorItem& other, int percent, int grayLevel ) -{ - if ( !_linkSrc ) - { - other._listeners.push_back(this); - _linkIsTone = true; - _linkPercent = percent; - if ( _linkPercent > 100 ) - _linkPercent = 100; - if ( _linkPercent < 0 ) - _linkPercent = 0; - _linkGray = grayLevel; - _linkSrc = &other; - - ColorItem::_colorDefChanged(&other); - } -} - - -void _loadPaletteFile( gchar const *filename ) -{ - char block[1024]; - FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" ); - if ( f ) { - char* result = fgets( block, sizeof(block), f ); - if ( result ) { - if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) { - bool inHeader = true; - bool hasErr = false; - - JustForNow *onceMore = new JustForNow(); - - do { - result = fgets( block, sizeof(block), f ); - block[sizeof(block) - 1] = 0; - if ( result ) { - if ( block[0] == '#' ) { - // ignore comment - } else { - char *ptr = block; - // very simple check for header versus entry - while ( *ptr == ' ' || *ptr == '\t' ) { - ptr++; - } - if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) { - // blank line. skip it. - } else if ( '0' <= *ptr && *ptr <= '9' ) { - // should be an entry link - inHeader = false; - ptr = block; - Glib::ustring name(""); - int r = 0; - int g = 0; - int b = 0; - skipWhitespace(ptr); - if ( *ptr ) { - hasErr = parseNum(ptr, r); - if ( !hasErr ) { - skipWhitespace(ptr); - hasErr = parseNum(ptr, g); - } - if ( !hasErr ) { - skipWhitespace(ptr); - hasErr = parseNum(ptr, b); - } - if ( !hasErr && *ptr ) { - char* n = trim(ptr); - if (n != NULL) { - name = n; - } - } - if ( !hasErr ) { - // Add the entry now - Glib::ustring nameStr(name); - ColorItem* item = new ColorItem( r, g, b, nameStr ); - onceMore->_colors.push_back(item); - } - } else { - hasErr = true; - } - } else { - if ( !inHeader ) { - // Hmmm... probably bad. Not quite the format we want? - hasErr = true; - } else { - char* sep = strchr(result, ':'); - if ( sep ) { - *sep = 0; - char* val = trim(sep + 1); - char* name = trim(result); - if ( *name ) { - if ( strcmp( "Name", name ) == 0 ) - { - onceMore->_name = val; - } - else if ( strcmp( "Columns", name ) == 0 ) - { - gchar* endPtr = 0; - guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 ); - if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { - // overflow - } else if ( (numVal == 0) && (endPtr == val) ) { - // failed conversion - } else { - onceMore->_prefWidth = numVal; - } - } - } else { - // error - hasErr = true; - } - } else { - // error - hasErr = true; - } - } - } - } - } - } while ( result && !hasErr ); - if ( !hasErr ) { - possible.push_back(onceMore); -#if ENABLE_MAGIC_COLORS - ColorItem::_wireMagicColors( onceMore ); -#endif // ENABLE_MAGIC_COLORS - } else { - delete onceMore; - } - } - } - - fclose(f); - } -} - -static void loadEmUp() -{ - static bool beenHere = false; - if ( !beenHere ) { - beenHere = true; - - std::list<gchar *> sources; - sources.push_back( profile_path("palettes") ); - sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) ); - sources.push_back( g_strdup(CREATE_PALETTESDIR) ); - - // Use this loop to iterate through a list of possible document locations. - while (!sources.empty()) { - gchar *dirname = sources.front(); - - if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS ) - && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) { - GError *err = 0; - GDir *directory = g_dir_open(dirname, 0, &err); - if (!directory) { - gchar *safeDir = Inkscape::IO::sanitizeString(dirname); - g_warning(_("Palettes directory (%s) is unavailable."), safeDir); - g_free(safeDir); - } else { - gchar *filename = 0; - while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) { - gchar* lower = g_ascii_strdown( filename, -1 ); -// if ( g_str_has_suffix(lower, ".gpl") ) { - gchar* full = g_build_filename(dirname, filename, NULL); - if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) { - _loadPaletteFile(full); - } - g_free(full); -// } - g_free(lower); - } - g_dir_close(directory); - } - } - - // toss the dirname - g_free(dirname); - sources.pop_front(); - } - } -} - - - - - - - - - -SwatchesPanel& SwatchesPanel::getInstance() -{ - return *new SwatchesPanel(); -} - - -/** - * Constructor - */ -SwatchesPanel::SwatchesPanel(gchar const* prefsPath) : - Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true), - _holder(0) -{ - Gtk::RadioMenuItem* hotItem = 0; - _holder = new PreviewHolder(); - _remove = new ColorItem(); - loadEmUp(); - if ( !possible.empty() ) { - JustForNow* first = 0; - Glib::ustring targetName; - if ( !_prefs_path.empty() ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - targetName = prefs->getString(_prefs_path + "/palette"); - if (!targetName.empty()) { - for ( std::vector<JustForNow*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) { - if ( (*iter)->_name == targetName ) { - first = *iter; - break; - } - } - } - } - - if ( !first ) { - first = possible.front(); - } - - if ( first->_prefWidth > 0 ) { - _holder->setColumnPref( first->_prefWidth ); - } - _holder->freezeUpdates(); - _holder->addPreview(_remove); - for ( std::vector<ColorItem*>::iterator it = first->_colors.begin(); it != first->_colors.end(); it++ ) { - _holder->addPreview(*it); - } - _holder->thawUpdates(); - - Gtk::RadioMenuItem::Group groupOne; - - int i = 0; - for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end(); it++ ) { - JustForNow* curr = *it; - Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name)); - if ( curr == first ) { - hotItem = single; - } - _regItem( single, 3, i ); - i++; - } - } - - - _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET); - _setTargetFillable(_holder); - - show_all_children(); - - restorePanelPrefs(); - if ( hotItem ) { - hotItem->set_active(); - } -} - -SwatchesPanel::~SwatchesPanel() -{ - if (_remove) delete _remove; - if (_holder) delete _holder; -} - -void SwatchesPanel::setOrientation( Gtk::AnchorType how ) -{ - // Must call the parent class or bad things might happen - Inkscape::UI::Widget::Panel::setOrientation( how ); - - if ( _holder ) - { - _holder->setOrientation( Gtk::ANCHOR_SOUTH ); - } -} - -void SwatchesPanel::_handleAction( int setId, int itemId ) -{ - switch( setId ) { - case 3: - { - if ( itemId >= 0 && itemId < static_cast<int>(possible.size()) ) { - _holder->clear(); - JustForNow* curr = possible[itemId]; - - if ( !_prefs_path.empty() ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString(_prefs_path + "/palette", curr->_name); - } - - if ( curr->_prefWidth > 0 ) { - _holder->setColumnPref( curr->_prefWidth ); - } - _holder->freezeUpdates(); - _holder->addPreview(_remove); - for ( std::vector<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { - _holder->addPreview(*it); - } - _holder->thawUpdates(); - } - } - break; - } -} - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/swatches.h b/src/dialogs/swatches.h deleted file mode 100644 index 00c73ff84..000000000 --- a/src/dialogs/swatches.h +++ /dev/null @@ -1,128 +0,0 @@ -/** @file - * @brief Color swatches dialog - */ -/* Authors: - * Jon A. Cruz - * - * Copyright (C) 2005 Jon A. Cruz - * Released under GNU GPL, read the file 'COPYING' for more information - */ -#ifndef SEEN_DIALOGS_SWATCHES_H -#define SEEN_DIALOGS_SWATCHES_H - -#include <gtkmm/textview.h> -#include <gtkmm/tooltips.h> - -#include "ui/widget/panel.h" -#include "ui/previewholder.h" -#include "dialogs/eek-color-def.h" - -using eek::ColorDef; - -namespace Inkscape { -namespace UI { -namespace Dialogs { - - -void _loadPaletteFile( gchar const *filename ); - -/** - * The color swatch you see on screen as a clickable box. - */ -class ColorItem : public Inkscape::UI::Previewable -{ - friend void _loadPaletteFile( gchar const *filename ); -public: - ColorItem(); - ColorItem( unsigned int r, unsigned int g, unsigned int b, - Glib::ustring& name ); - virtual ~ColorItem(); - ColorItem(ColorItem const &other); - virtual ColorItem &operator=(ColorItem const &other); - virtual Gtk::Widget* getPreview(PreviewStyle style, - ViewType view, - ::PreviewSize size, - guint ratio); - void buttonClicked(bool secondary = false); - bool isRemove(){ return _isRemove; } - ColorDef def; - -private: - static void _dropDataIn( GtkWidget *widget, - GdkDragContext *drag_context, - gint x, gint y, - GtkSelectionData *data, - guint info, - guint event_time, - gpointer user_data); - - static void _dragGetColorData( GtkWidget *widget, - GdkDragContext *drag_context, - GtkSelectionData *data, - guint info, - guint time, - gpointer user_data); - - static void _wireMagicColors( void* p ); - static void _colorDefChanged(void* data); - - void _linkTint( ColorItem& other, int percent ); - void _linkTone( ColorItem& other, int percent, int grayLevel ); - - Gtk::Tooltips tips; - std::vector<Gtk::Widget*> _previews; - - bool _isRemove; - bool _isLive; - bool _linkIsTone; - int _linkPercent; - int _linkGray; - ColorItem* _linkSrc; - std::vector<ColorItem*> _listeners; -}; - -class RemoveColorItem; - -/** - * A panel that displays color swatches. - */ -class SwatchesPanel : public Inkscape::UI::Widget::Panel -{ -public: - SwatchesPanel(gchar const* prefsPath = "/dialogs/swatches"); - virtual ~SwatchesPanel(); - - static SwatchesPanel& getInstance(); - virtual void setOrientation( Gtk::AnchorType how ); - -protected: - virtual void _handleAction( int setId, int itemId ); - -private: - SwatchesPanel(SwatchesPanel const &); // no copy - SwatchesPanel &operator=(SwatchesPanel const &); // no assign - - static SwatchesPanel* instance; - - PreviewHolder* _holder; - ColorItem* _remove; -}; - -} //namespace Dialogs -} //namespace UI -} //namespace Inkscape - - - -#endif // SEEN_SWATCHES_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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/unclump.cpp b/src/dialogs/unclump.cpp deleted file mode 100644 index aebcfd908..000000000 --- a/src/dialogs/unclump.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/** @file - * @brief Unclumping objects - */ -/* Authors: - * bulia byak - * - * Copyright (C) 2005 Authors - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <algorithm> -#include <map> -#include "sp-item.h" - - -// Taking bbox of an item is an expensive operation, and we need to do it many times, so here we -// cache the centers, widths, and heights of items - -//FIXME: make a class with these cashes as members instead of globals -std::map<const gchar *, Geom::Point> c_cache; -std::map<const gchar *, Geom::Point> wh_cache; - -/** -Center of bbox of item -*/ -Geom::Point -unclump_center (SPItem *item) -{ - std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(item)); - if ( i != c_cache.end() ) { - return i->second; - } - - Geom::OptRect r = item->getBounds(sp_item_i2d_affine(item)); - if (r) { - Geom::Point const c = r->midpoint(); - c_cache[SP_OBJECT_ID(item)] = c; - return c; - } else { - // FIXME - return Geom::Point(0, 0); - } -} - -Geom::Point -unclump_wh (SPItem *item) -{ - Geom::Point wh; - std::map<const gchar *, Geom::Point>::iterator i = wh_cache.find(SP_OBJECT_ID(item)); - if ( i != wh_cache.end() ) { - wh = i->second; - } else { - Geom::OptRect r = item->getBounds(sp_item_i2d_affine(item)); - if (r) { - wh = r->dimensions(); - wh_cache[SP_OBJECT_ID(item)] = wh; - } else { - wh = Geom::Point(0, 0); - } - } - - return wh; -} - -/** -Distance between "edges" of item1 and item2. An item is considered to be an ellipse inscribed into its w/h, -so its radius (distance from center to edge) depends on the w/h and the angle towards the other item. -May be negative if the edge of item1 is between the center and the edge of item2. -*/ -double -unclump_dist (SPItem *item1, SPItem *item2) -{ - Geom::Point c1 = unclump_center (item1); - Geom::Point c2 = unclump_center (item2); - - Geom::Point wh1 = unclump_wh (item1); - Geom::Point wh2 = unclump_wh (item2); - - // angle from each item's center to the other's, unsqueezed by its w/h, normalized to 0..pi/2 - double a1 = atan2 ((c2 - c1)[Geom::Y], (c2 - c1)[Geom::X] * wh1[Geom::Y]/wh1[Geom::X]); - a1 = fabs (a1); - if (a1 > M_PI/2) a1 = M_PI - a1; - - double a2 = atan2 ((c1 - c2)[Geom::Y], (c1 - c2)[Geom::X] * wh2[Geom::Y]/wh2[Geom::X]); - a2 = fabs (a2); - if (a2 > M_PI/2) a2 = M_PI - a2; - - // get the radius of each item for the given angle - double r1 = 0.5 * (wh1[Geom::X] + (wh1[Geom::Y] - wh1[Geom::X]) * (a1/(M_PI/2))); - double r2 = 0.5 * (wh2[Geom::X] + (wh2[Geom::Y] - wh2[Geom::X]) * (a2/(M_PI/2))); - - // dist between centers minus angle-adjusted radii - double dist_r = (Geom::L2 (c2 - c1) - r1 - r2); - - double stretch1 = wh1[Geom::Y]/wh1[Geom::X]; - double stretch2 = wh2[Geom::Y]/wh2[Geom::X]; - - if ((stretch1 > 1.5 || stretch1 < 0.66) && (stretch2 > 1.5 || stretch2 < 0.66)) { - - std::vector<double> dists; - dists.push_back (dist_r); - - // If both objects are not circle-like, find dists between four corners - std::vector<Geom::Point> c1_points(2); - { - double y_closest; - if (c2[Geom::Y] > c1[Geom::Y] + wh1[Geom::Y]/2) { - y_closest = c1[Geom::Y] + wh1[Geom::Y]/2; - } else if (c2[Geom::Y] < c1[Geom::Y] - wh1[Geom::Y]/2) { - y_closest = c1[Geom::Y] - wh1[Geom::Y]/2; - } else { - y_closest = c2[Geom::Y]; - } - c1_points[0] = Geom::Point (c1[Geom::X], y_closest); - double x_closest; - if (c2[Geom::X] > c1[Geom::X] + wh1[Geom::X]/2) { - x_closest = c1[Geom::X] + wh1[Geom::X]/2; - } else if (c2[Geom::X] < c1[Geom::X] - wh1[Geom::X]/2) { - x_closest = c1[Geom::X] - wh1[Geom::X]/2; - } else { - x_closest = c2[Geom::X]; - } - c1_points[1] = Geom::Point (x_closest, c1[Geom::Y]); - } - - - std::vector<Geom::Point> c2_points(2); - { - double y_closest; - if (c1[Geom::Y] > c2[Geom::Y] + wh2[Geom::Y]/2) { - y_closest = c2[Geom::Y] + wh2[Geom::Y]/2; - } else if (c1[Geom::Y] < c2[Geom::Y] - wh2[Geom::Y]/2) { - y_closest = c2[Geom::Y] - wh2[Geom::Y]/2; - } else { - y_closest = c1[Geom::Y]; - } - c2_points[0] = Geom::Point (c2[Geom::X], y_closest); - double x_closest; - if (c1[Geom::X] > c2[Geom::X] + wh2[Geom::X]/2) { - x_closest = c2[Geom::X] + wh2[Geom::X]/2; - } else if (c1[Geom::X] < c2[Geom::X] - wh2[Geom::X]/2) { - x_closest = c2[Geom::X] - wh2[Geom::X]/2; - } else { - x_closest = c1[Geom::X]; - } - c2_points[1] = Geom::Point (x_closest, c2[Geom::Y]); - } - - for (int i = 0; i < 2; i ++) { - for (int j = 0; j < 2; j ++) { - dists.push_back (Geom::L2 (c1_points[i] - c2_points[j])); - } - } - - // return the minimum of all dists - return *std::min_element(dists.begin(), dists.end()); - } else { - return dist_r; - } -} - -/** -Average unclump_dist from item to others -*/ -double unclump_average (SPItem *item, GSList *others) -{ - int n = 0; - double sum = 0; - - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); - - if (other == item) - continue; - - n++; - sum += unclump_dist (item, other); - } - - if (n != 0) - return sum/n; - else - return 0; -} - -/** -Closest to item among others - */ -SPItem *unclump_closest (SPItem *item, GSList *others) -{ - double min = HUGE_VAL; - SPItem *closest = NULL; - - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); - - if (other == item) - continue; - - double dist = unclump_dist (item, other); - if (dist < min && fabs (dist) < 1e6) { - min = dist; - closest = other; - } - } - - return closest; -} - -/** -Most distant from item among others - */ -SPItem *unclump_farest (SPItem *item, GSList *others) -{ - double max = -HUGE_VAL; - SPItem *farest = NULL; - - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); - - if (other == item) - continue; - - double dist = unclump_dist (item, other); - if (dist > max && fabs (dist) < 1e6) { - max = dist; - farest = other; - } - } - - return farest; -} - -/** -Removes from the \a rest list those items that are "behind" \a closest as seen from \a item, -i.e. those on the other side of the line through \a closest perpendicular to the direction from \a -item to \a closest. Returns a newly created list which must be freed. - */ -GSList * -unclump_remove_behind (SPItem *item, SPItem *closest, GSList *rest) -{ - Geom::Point it = unclump_center (item); - Geom::Point p1 = unclump_center (closest); - - // perpendicular through closest to the direction to item: - Geom::Point perp = Geom::rot90(it - p1); - Geom::Point p2 = p1 + perp; - - // get the standard Ax + By + C = 0 form for p1-p2: - double A = p1[Geom::Y] - p2[Geom::Y]; - double B = p2[Geom::X] - p1[Geom::X]; - double C = p2[Geom::Y] * p1[Geom::X] - p1[Geom::Y] * p2[Geom::X]; - - // substitute the item into it: - double val_item = A * it[Geom::X] + B * it[Geom::Y] + C; - - GSList *out = NULL; - - for (GSList *i = rest; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); - - if (other == item) - continue; - - Geom::Point o = unclump_center (other); - double val_other = A * o[Geom::X] + B * o[Geom::Y] + C; - - if (val_item * val_other <= 1e-6) { - // different signs, which means item and other are on the different sides of p1-p2 line; skip - } else { - out = g_slist_prepend (out, other); - } - } - - return out; -} - -/** -Moves \a what away from \a from by \a dist - */ -void -unclump_push (SPItem *from, SPItem *what, double dist) -{ - Geom::Point it = unclump_center (what); - Geom::Point p = unclump_center (from); - Geom::Point by = dist * Geom::unit_vector (- (p - it)); - - Geom::Matrix move = Geom::Translate (by); - - std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(what)); - if ( i != c_cache.end() ) { - i->second *= move; - } - - //g_print ("push %s at %g,%g from %g,%g by %g,%g, dist %g\n", SP_OBJECT_ID(what), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); - - sp_item_set_i2d_affine(what, sp_item_i2d_affine(what) * move); - sp_item_write_transform(what, SP_OBJECT_REPR(what), what->transform, NULL); -} - -/** -Moves \a what towards \a to by \a dist - */ -void -unclump_pull (SPItem *to, SPItem *what, double dist) -{ - Geom::Point it = unclump_center (what); - Geom::Point p = unclump_center (to); - Geom::Point by = dist * Geom::unit_vector (p - it); - - Geom::Matrix move = Geom::Translate (by); - - std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(what)); - if ( i != c_cache.end() ) { - i->second *= move; - } - - //g_print ("pull %s at %g,%g to %g,%g by %g,%g, dist %g\n", SP_OBJECT_ID(what), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); - - sp_item_set_i2d_affine(what, sp_item_i2d_affine(what) * move); - sp_item_write_transform(what, SP_OBJECT_REPR(what), what->transform, NULL); -} - - -/** -Unclumps the items in \a items, reducing local unevenness in their distribution. Produces an effect -similar to "engraver dots". The only distribution which is unchanged by unclumping is a hexagonal -grid. May be called repeatedly for stronger effect. - */ -void -unclump (GSList *items) -{ - c_cache.clear(); - wh_cache.clear(); - - for (GSList *i = items; i != NULL; i = i->next) { // for each original/clone x: - SPItem *item = SP_ITEM (i->data); - - GSList *nei = NULL; - - GSList *rest = g_slist_copy (items); - rest = g_slist_remove (rest, item); - - while (rest != NULL) { - SPItem *closest = unclump_closest (item, rest); - if (closest) { - nei = g_slist_prepend (nei, closest); - rest = g_slist_remove (rest, closest); - GSList *new_rest = unclump_remove_behind (item, closest, rest); - g_slist_free (rest); - rest = new_rest; - } else { - g_slist_free (rest); - break; - } - } - - if (g_slist_length (nei) >= 2) { - double ave = unclump_average (item, nei); - - SPItem *closest = unclump_closest (item, nei); - SPItem *farest = unclump_farest (item, nei); - - double dist_closest = unclump_dist (closest, item); - double dist_farest = unclump_dist (farest, item); - - //g_print ("NEI %d for item %s closest %s at %g farest %s at %g ave %g\n", g_slist_length(nei), SP_OBJECT_ID(item), SP_OBJECT_ID(closest), dist_closest, SP_OBJECT_ID(farest), dist_farest, ave); - - if (fabs (ave) < 1e6 && fabs (dist_closest) < 1e6 && fabs (dist_farest) < 1e6) { // otherwise the items are bogus - // increase these coefficients to make unclumping more aggressive and less stable - // the pull coefficient is a bit bigger to counteract the long-term expansion trend - unclump_push (closest, item, 0.3 * (ave - dist_closest)); - unclump_pull (farest, item, 0.35 * (dist_farest - ave)); - } - } - } -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/unclump.h b/src/dialogs/unclump.h deleted file mode 100644 index c5a8bf7d7..000000000 --- a/src/dialogs/unclump.h +++ /dev/null @@ -1,29 +0,0 @@ -/** @file - * @brief Unclumping objects - */ -/* Authors: - * bulia byak - * - * Copyright (C) 2005 Authors - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_DIALOGS_UNCLUMP_H -#define SEEN_DIALOGS_UNCLUMP_H - -#include <glib/gslist.h> - -void unclump(GSList *items); - -#endif /* !UNCLUMP_H_SEEN */ - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/dialogs/xml-tree.cpp b/src/dialogs/xml-tree.cpp index 65ae9a8a3..cf3599517 100644 --- a/src/dialogs/xml-tree.cpp +++ b/src/dialogs/xml-tree.cpp @@ -22,7 +22,6 @@ #include "../document.h" #include "../event-context.h" #include "helper/window.h" -#include "in-dt-coordsys.h" #include "../inkscape.h" #include "../interface.h" #include "macros.h" @@ -142,6 +141,7 @@ static void cmd_set_attr(GtkObject *object, gpointer data); static gboolean sp_xml_tree_key_press(GtkWidget *widget, GdkEventKey *event); +static bool in_dt_coordsys(SPObject const &item); /* * \brief Sets the XML status bar when the tree is selected. @@ -1574,6 +1574,31 @@ void cmd_unindent_node(GtkObject */*object*/, gpointer /*data*/) } // end of cmd_unindent_node() +/** Returns true iff \a item is suitable to be included in the selection, in particular + whether it has a bounding box in the desktop coordinate system for rendering resize handles. + + Descendents of <defs> nodes (markers etc.) return false, for example. +*/ +bool in_dt_coordsys(SPObject const &item) +{ + /* Definition based on sp_item_i2doc_affine. */ + SPObject const *child = &item; + g_return_val_if_fail(child != NULL, false); + for(;;) { + if (!SP_IS_ITEM(child)) { + return false; + } + SPObject const * const parent = SP_OBJECT_PARENT(child); + if (parent == NULL) { + break; + } + child = parent; + } + g_assert(SP_IS_ROOT(child)); + /* Relevance: Otherwise, I'm not sure whether to return true or false. */ + return true; +} + /* Local Variables: diff --git a/src/document.cpp b/src/document.cpp index 4f5487032..fe6ce011b 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -40,29 +40,27 @@ #include <gtk/gtkmain.h> #include <string> #include <cstring> + #include "application/application.h" #include "application/editor.h" -#include "xml/repr.h" +#include "desktop.h" +#include "dir-util.h" +#include "display/nr-arena-item.h" +#include "document-private.h" #include "helper/units.h" #include "inkscape-private.h" #include "inkscape-version.h" -#include "sp-object-repr.h" -#include "sp-namedview.h" -#include "desktop.h" -#include "document-private.h" -#include "dir-util.h" -#include "unit-constants.h" -#include "preferences.h" #include "libavoid/router.h" -#include "sp-item-group.h" -#include "profile-manager.h" #include "persp3d.h" - -#include "display/nr-arena-item.h" - -#include "dialogs/rdf.h" - +#include "preferences.h" +#include "profile-manager.h" +#include "rdf.h" +#include "sp-item-group.h" +#include "sp-namedview.h" +#include "sp-object-repr.h" #include "transf_mat_3x4.h" +#include "unit-constants.h" +#include "xml/repr.h" #define SP_DOCUMENT_UPDATE_PRIORITY (G_PRIORITY_HIGH_IDLE - 1) diff --git a/src/extension/error-file.cpp b/src/extension/error-file.cpp index 7e40522b3..5a3f8dcd2 100644 --- a/src/extension/error-file.cpp +++ b/src/extension/error-file.cpp @@ -17,7 +17,7 @@ #include "inkscape.h" #include "preferences.h" -#include "dialogs/extensions.h" +#include "ui/dialog/extensions.h" #include "extension/extension.h" #include "error-file.h" diff --git a/src/file.cpp b/src/file.cpp index 5c729eeeb..396e9095f 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1,9 +1,7 @@ -#define __SP_FILE_C__ - -/* - * File/Print operations - * - * Authors: +/** @file + * @brief File/Print operations + */ +/* Authors: * Lauris Kaplinski <lauris@kaplinski.com> * Chema Celorio <chema@celorio.com> * bulia byak <buliabyak@users.sf.net> @@ -30,45 +28,41 @@ #include <gtk/gtk.h> #include <glib/gmem.h> +#include <glibmm/i18n.h> #include <libnr/nr-pixops.h> -#include "document-private.h" -#include "selection-chemistry.h" -#include "ui/view/view-widget.h" +#include "application/application.h" +#include "application/editor.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "dialogs/export.h" #include "dir-util.h" +#include "document-private.h" +#include "extension/db.h" +#include "extension/input.h" +#include "extension/output.h" +#include "extension/system.h" +#include "file.h" #include "helper/png-write.h" -#include "dialogs/export.h" -#include <glibmm/i18n.h> +#include "id-clash.h" +#include "inkscape.h" #include "inkscape.h" -#include "desktop.h" -#include "selection.h" #include "interface.h" -#include "style.h" -#include "print.h" -#include "file.h" +#include "io/sys.h" #include "message.h" #include "message-stack.h" -#include "ui/dialog/filedialog.h" -#include "ui/dialog/ocaldialogs.h" -#include "preferences.h" #include "path-prefix.h" - +#include "preferences.h" +#include "print.h" +#include "rdf.h" +#include "selection-chemistry.h" +#include "selection.h" #include "sp-namedview.h" -#include "desktop-handles.h" - -#include "extension/db.h" -#include "extension/input.h" -#include "extension/output.h" -/* #include "extension/menu.h" */ -#include "extension/system.h" - -#include "io/sys.h" -#include "application/application.h" -#include "application/editor.h" -#include "inkscape.h" +#include "style.h" +#include "ui/dialog/filedialog.h" +#include "ui/dialog/ocaldialogs.h" +#include "ui/view/view-widget.h" #include "uri.h" -#include "id-clash.h" -#include "dialogs/rdf.h" #ifdef WITH_GNOME_VFS # include <libgnomevfs/gnome-vfs.h> diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 753b0df45..ee17e7079 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -31,7 +31,7 @@ #include <sp-root.h> #include <sp-defs.h> #include "preferences.h" -#include "dialogs/rdf.h" +#include "rdf.h" /* This is an example of how to use libpng to read and write PNG files. * The file libpng.txt is much more verbose then this. If you have not diff --git a/src/rdf.cpp b/src/rdf.cpp new file mode 100644 index 000000000..f0b174922 --- /dev/null +++ b/src/rdf.cpp @@ -0,0 +1,1023 @@ +/** @file + * @brief RDF manipulation functions + * + * @todo move these to xml/ instead of dialogs/ + */ +/* Authors: + * Kees Cook <kees@outflux.net> + * Jon Phillips <jon@rejon.org> + * + * Copyright (C) 2004 Kees Cook <kees@outflux.net> + * Copyright (C) 2006 Jon Phillips <jon@rejon.org> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "xml/repr.h" +#include "rdf.h" +#include "sp-item-group.h" +#include "inkscape.h" + +/* + Example RDF XML from various places... + +<rdf:RDF xmlns="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +<Work rdf:about=""> + <dc:title>title of work</dc:title> + <dc:date>year</dc:date> + <dc:description>description of work</dc:description> + <dc:creator><Agent> + <dc:title>creator</dc:title> + </Agent></dc:creator> + <dc:rights><Agent> + <dc:title>holder</dc:title> + </Agent></dc:rights> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:source rdf:resource="source"/> + <license rdf:resource="http://creativecommons.org/licenses/by/2.0/" +/> +</Work> + + + <rdf:RDF xmlns="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <Work rdf:about=""> + <dc:title>SVG Road Signs</dc:title> + <dc:rights><Agent> + <dc:title>John Cliff</dc:title> + </Agent></dc:rights> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <license rdf:resource="http://creativecommons.org/ns#PublicDomain" /> + </Work> + + <License rdf:about="http://creativecommons.org/ns#PublicDomain"> + <permits rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <permits rdf:resource="http://creativecommons.org/ns#Distribution" /> + <permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </License> + +</rdf:RDF> + + +Bag example: + +<dc:subject> +<rdf:Bag> +<rdf:li>open clip art logo</rdf:li> +<rdf:li>images</rdf:li> +<rdf:li>logo</rdf:li> +<rdf:li>clip art</rdf:li> +<rdf:li>ocal</rdf:li> +<rdf:li>logotype</rdf:li> +<rdf:li>filetype</rdf:li> +</rdf:Bag> +</dc:subject> +*/ + +struct rdf_double_t rdf_license_empty [] = { + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a_sa [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a_nd [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a_nc [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a_nc_sa [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_cc_a_nc_nd [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { "cc:prohibits", "http://creativecommons.org/ns#CommercialUse", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_pd [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_freeart [] = { + { "cc:permits", "http://creativecommons.org/ns#Reproduction", }, + { "cc:permits", "http://creativecommons.org/ns#Distribution", }, + { "cc:permits", "http://creativecommons.org/ns#DerivativeWorks", }, + { "cc:requires", "http://creativecommons.org/ns#ShareAlike", }, + { "cc:requires", "http://creativecommons.org/ns#Notice", }, + { "cc:requires", "http://creativecommons.org/ns#Attribution", }, + { NULL, NULL } +}; + +struct rdf_double_t rdf_license_ofl [] = { + { "cc:permits", "http://scripts.sil.org/pub/OFL/Reproduction", }, + { "cc:permits", "http://scripts.sil.org/pub/OFL/Distribution", }, + { "cc:permits", "http://scripts.sil.org/pub/OFL/Embedding", }, + { "cc:permits", "http://scripts.sil.org/pub/OFL/DerivativeWorks", }, + { "cc:requires", "http://scripts.sil.org/pub/OFL/Notice", }, + { "cc:requires", "http://scripts.sil.org/pub/OFL/Attribution", }, + { "cc:requires", "http://scripts.sil.org/pub/OFL/ShareAlike", }, + { "cc:requires", "http://scripts.sil.org/pub/OFL/DerivativeRenaming", }, + { "cc:requires", "http://scripts.sil.org/pub/OFL/BundlingWhenSelling", }, + { NULL, NULL } +}; + +struct rdf_license_t rdf_licenses [] = { + { N_("CC Attribution"), + "http://creativecommons.org/licenses/by/3.0/", + rdf_license_cc_a, + }, + + { N_("CC Attribution-ShareAlike"), + "http://creativecommons.org/licenses/by-sa/3.0/", + rdf_license_cc_a_sa, + }, + + { N_("CC Attribution-NoDerivs"), + "http://creativecommons.org/licenses/by-nd/3.0/", + rdf_license_cc_a_nd, + }, + + { N_("CC Attribution-NonCommercial"), + "http://creativecommons.org/licenses/by-nc/3.0/", + rdf_license_cc_a_nc, + }, + + { N_("CC Attribution-NonCommercial-ShareAlike"), + "http://creativecommons.org/licenses/by-nc-sa/3.0/", + rdf_license_cc_a_nc_sa, + }, + + { N_("CC Attribution-NonCommercial-NoDerivs"), + "http://creativecommons.org/licenses/by-nc-nd/3.0/", + rdf_license_cc_a_nc_nd, + }, + + { N_("Public Domain"), + "http://creativecommons.org/licenses/publicdomain/", + rdf_license_pd, + }, + + { N_("FreeArt"), + "http://artlibre.org/licence.php/lalgb.html", + rdf_license_freeart, + }, + + { N_("Open Font License"), + "http://scripts.sil.org/OFL", + rdf_license_ofl, + }, + + { NULL, NULL, rdf_license_empty, } +}; + +#define XML_TAG_NAME_SVG "svg:svg" +#define XML_TAG_NAME_METADATA "svg:metadata" +#define XML_TAG_NAME_RDF "rdf:RDF" +#define XML_TAG_NAME_WORK "cc:Work" +#define XML_TAG_NAME_LICENSE "cc:License" + +// Remember when using the "title" and "tip" elements to pass them through +// the localization functions when you use them! +struct rdf_work_entity_t rdf_work_entities [] = { + { "title", N_("Title"), "dc:title", RDF_CONTENT, + N_("Name by which this document is formally known."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "date", N_("Date"), "dc:date", RDF_CONTENT, + N_("Date associated with the creation of this document (YYYY-MM-DD)."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "format", N_("Format"), "dc:format", RDF_CONTENT, + N_("The physical or digital manifestation of this document (MIME type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, + }, + { "type", N_("Type"), "dc:type", RDF_RESOURCE, + N_("Type of document (DCMI Type)."), RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, + }, + + { "creator", N_("Creator"), "dc:creator", RDF_AGENT, + N_("Name of entity primarily responsible for making the content of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "rights", N_("Rights"), "dc:rights", RDF_AGENT, + N_("Name of entity with rights to the Intellectual Property of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "publisher", N_("Publisher"), "dc:publisher", RDF_AGENT, + N_("Name of entity responsible for making this document available."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + + { "identifier", N_("Identifier"), "dc:identifier", RDF_CONTENT, + N_("Unique URI to reference this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "source", N_("Source"), "dc:source", RDF_CONTENT, + N_("Unique URI to reference the source of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "relation", N_("Relation"), "dc:relation", RDF_CONTENT, + N_("Unique URI to a related document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "language", N_("Language"), "dc:language", RDF_CONTENT, + N_("Two-letter language tag with optional subtags for the language of this document. (e.g. 'en-GB')"), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + { "subject", N_("Keywords"), "dc:subject", RDF_BAG, + N_("The topic of this document as comma-separated key words, phrases, or classifications."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + // TRANSLATORS: "Coverage": the spatial or temporal characteristics of the content. + // For info, see Appendix D of http://www.w3.org/TR/1998/WD-rdf-schema-19980409/ + { "coverage", N_("Coverage"), "dc:coverage", RDF_CONTENT, + N_("Extent or scope of this document."), RDF_FORMAT_LINE, RDF_EDIT_GENERIC, + }, + + { "description", N_("Description"), "dc:description", RDF_CONTENT, + N_("A short account of the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC, + }, + + // FIXME: need to handle 1 agent per line of input + { "contributor", N_("Contributors"), "dc:contributor", RDF_AGENT, + N_("Names of entities responsible for making contributions to the content of this document."), RDF_FORMAT_MULTILINE, RDF_EDIT_GENERIC, + }, + + // TRANSLATORS: URL to a page that defines the license for the document + { "license_uri", N_("URI"), "cc:license", RDF_RESOURCE, + // TRANSLATORS: this is where you put a URL to a page that defines the license + N_("URI to this document's license's namespace definition."), RDF_FORMAT_LINE, RDF_EDIT_SPECIAL, + }, + + // TRANSLATORS: fragment of XML representing the license of the document + { "license_fragment", N_("Fragment"), "License", RDF_XML, + N_("XML fragment for the RDF 'License' section."), RDF_FORMAT_MULTILINE, RDF_EDIT_SPECIAL, + }, + + { NULL, NULL, NULL, RDF_CONTENT, + NULL, RDF_FORMAT_LINE, RDF_EDIT_HARDCODED, + } +}; + +/** + * \brief Retrieves a known RDF/Work entity by name + * \return A pointer to an RDF/Work entity + * \param name The desired RDF/Work entity + * + */ +struct rdf_work_entity_t * +rdf_find_entity(gchar const * name) +{ + struct rdf_work_entity_t *entity; + for (entity=rdf_work_entities; entity->name; entity++) { + if (strcmp(entity->name,name)==0) break; + } + if (entity->name) return entity; + return NULL; +} + +/* + * Takes the inkscape rdf struct and spits out a static RDF, which is only + * useful for testing. We must merge the rdf struct into the XML DOM for + * changes to be saved. + */ +/* + + Since g_markup_printf_escaped doesn't exist for most people's glib + right now, this function will remain commented out since it's only + for generic debug anyway. --Kees + +gchar * +rdf_string(struct rdf_t * rdf) +{ + gulong overall=0; + gchar *string=NULL; + + gchar *rdf_head="\ +<rdf:RDF xmlns=\"http://creativecommons.org/ns#\"\ + xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\ + xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\ +"; + gchar *work_head="\ +<Work rdf:about=\"\">\ + <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\ +"; + gchar *work_title=NULL; + gchar *work_date=NULL; + gchar *work_description=NULL; + gchar *work_creator=NULL; + gchar *work_owner=NULL; + gchar *work_source=NULL; + gchar *work_license=NULL; + gchar *license_head=NULL; + gchar *license=NULL; + gchar *license_end="</License>\n"; + gchar *work_end="</Work>\n"; + gchar *rdf_end="</rdf:RDF>\n"; + + if (rdf && rdf->work_title && rdf->work_title[0]) { + work_title=g_markup_printf_escaped(" <dc:title>%s</dc:title>\n", + rdf->work_title); + overall+=strlen(work_title); + } + if (rdf && rdf->work_date && rdf->work_date[0]) { + work_date=g_markup_printf_escaped(" <dc:date>%s</dc:date>\n", + rdf->work_date); + overall+=strlen(work_date); + } + if (rdf && rdf->work_description && rdf->work_description[0]) { + work_description=g_markup_printf_escaped(" <dc:description>%s</dc:description>\n", + rdf->work_description); + overall+=strlen(work_description); + } + if (rdf && rdf->work_creator && rdf->work_creator[0]) { + work_creator=g_markup_printf_escaped(" <dc:creator><Agent>\ + <dc:title>%s</dc:title>\ + </Agent></dc:creator>\n", + rdf->work_creator); + overall+=strlen(work_creator); + } + if (rdf && rdf->work_owner && rdf->work_owner[0]) { + work_owner=g_markup_printf_escaped(" <dc:rights><Agent>\ + <dc:title>%s</dc:title>\ + </Agent></dc:rights>\n", + rdf->work_owner); + overall+=strlen(work_owner); + } + if (rdf && rdf->work_source && rdf->work_source[0]) { + work_source=g_markup_printf_escaped(" <dc:source rdf:resource=\"%s\" />\n", + rdf->work_source); + overall+=strlen(work_source); + } + if (rdf && rdf->license && rdf->license->work_rdf && rdf->license->work_rdf[0]) { + work_license=g_markup_printf_escaped(" <license rdf:resource=\"%s\" />\n", + rdf->license->work_rdf); + overall+=strlen(work_license); + + license_head=g_markup_printf_escaped("<License rdf:about=\"%s\">\n", + rdf->license->work_rdf); + overall+=strlen(license_head); + overall+=strlen(rdf->license->license_rdf); + overall+=strlen(license_end); + } + + overall+=strlen(rdf_head)+strlen(rdf_end); + overall+=strlen(work_head)+strlen(work_end); + + overall++; // NULL term + + if (!(string=(gchar*)g_malloc(overall))) { + return NULL; + } + + string[0]='\0'; + strcat(string,rdf_head); + strcat(string,work_head); + + if (work_title) strcat(string,work_title); + if (work_date) strcat(string,work_date); + if (work_description) strcat(string,work_description); + if (work_creator) strcat(string,work_creator); + if (work_owner) strcat(string,work_owner); + if (work_source) strcat(string,work_source); + if (work_license) strcat(string,work_license); + + strcat(string,work_end); + if (license_head) { + strcat(string,license_head); + strcat(string,rdf->license->license_rdf); + strcat(string,license_end); + } + strcat(string,rdf_end); + + return string; +} +*/ + + +/** + * \brief Pull the text out of an RDF entity, depends on how it's stored + * \return A pointer to the entity's static contents as a string + * \param repr The XML element to extract from + * \param entity The desired RDF/Work entity + * + */ +const gchar * +rdf_get_repr_text ( Inkscape::XML::Node * repr, struct rdf_work_entity_t * entity ) +{ + g_return_val_if_fail (repr != NULL, NULL); + g_return_val_if_fail (entity != NULL, NULL); + static gchar * bag = NULL; + gchar * holder = NULL; + + Inkscape::XML::Node * temp=NULL; + switch (entity->datatype) { + case RDF_CONTENT: + temp = sp_repr_children(repr); + if ( temp == NULL ) return NULL; + + return temp->content(); + + case RDF_AGENT: + temp = sp_repr_lookup_name ( repr, "cc:Agent", 1 ); + if ( temp == NULL ) return NULL; + + temp = sp_repr_lookup_name ( temp, "dc:title", 1 ); + if ( temp == NULL ) return NULL; + + temp = sp_repr_children(temp); + if ( temp == NULL ) return NULL; + + return temp->content(); + + case RDF_RESOURCE: + return repr->attribute("rdf:resource"); + + case RDF_XML: + return "xml goes here"; + + case RDF_BAG: + /* clear the static string. yucky. */ + if (bag) g_free(bag); + bag = NULL; + + temp = sp_repr_lookup_name ( repr, "rdf:Bag", 1 ); + if ( temp == NULL ) { + /* backwards compatible: read contents */ + temp = sp_repr_children(repr); + if ( temp == NULL ) return NULL; + + return temp->content(); + } + + for ( temp = sp_repr_children(temp) ; + temp ; + temp = sp_repr_next(temp) ) { + if (!strcmp(temp->name(),"rdf:li") && + temp->firstChild()) { + const gchar * str = temp->firstChild()->content(); + if (bag) { + holder = bag; + bag = g_strconcat(holder, ", ", str, NULL); + g_free(holder); + } + else { + bag = g_strdup(str); + } + } + } + return bag; + + default: + break; + } + return NULL; +} + +unsigned int +rdf_set_repr_text ( Inkscape::XML::Node * repr, + struct rdf_work_entity_t * entity, + gchar const * text ) +{ + g_return_val_if_fail ( repr != NULL, 0); + g_return_val_if_fail ( entity != NULL, 0); + g_return_val_if_fail ( text != NULL, 0); + gchar * str = NULL; + gchar** strlist = NULL; + int i; + + Inkscape::XML::Node * temp=NULL; + Inkscape::XML::Node * child=NULL; + Inkscape::XML::Node * parent=repr; + + Inkscape::XML::Document * xmldoc = parent->document(); + g_return_val_if_fail (xmldoc != NULL, FALSE); + + // set document's title element to the RDF title + if (!strcmp(entity->name, "title")) { + SPDocument *doc = SP_ACTIVE_DOCUMENT; + if(doc && doc->root) doc->root->setTitle(text); + } + + switch (entity->datatype) { + case RDF_CONTENT: + temp = sp_repr_children(parent); + if ( temp == NULL ) { + temp = xmldoc->createTextNode( text ); + g_return_val_if_fail (temp != NULL, FALSE); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + + return TRUE; + } + else { + temp->setContent(text); + return TRUE; + } + + case RDF_AGENT: + temp = sp_repr_lookup_name ( parent, "cc:Agent", 1 ); + if ( temp == NULL ) { + temp = xmldoc->createElement ( "cc:Agent" ); + g_return_val_if_fail (temp != NULL, FALSE); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + } + parent = temp; + + temp = sp_repr_lookup_name ( parent, "dc:title", 1 ); + if ( temp == NULL ) { + temp = xmldoc->createElement ( "dc:title" ); + g_return_val_if_fail (temp != NULL, FALSE); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + } + parent = temp; + + temp = sp_repr_children(parent); + if ( temp == NULL ) { + temp = xmldoc->createTextNode( text ); + g_return_val_if_fail (temp != NULL, FALSE); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + + return TRUE; + } + else { + temp->setContent(text); + return TRUE; + } + + case RDF_RESOURCE: + parent->setAttribute("rdf:resource", text ); + return true; + + case RDF_XML: + return 1; + + case RDF_BAG: + /* find/create the rdf:Bag item */ + temp = sp_repr_lookup_name ( parent, "rdf:Bag", 1 ); + if ( temp == NULL ) { + /* backward compatibility: drop the dc:subject contents */ + while ( (temp = sp_repr_children( parent )) ) { + parent->removeChild(temp); + } + + temp = xmldoc->createElement ( "rdf:Bag" ); + g_return_val_if_fail (temp != NULL, FALSE); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + } + parent = temp; + + /* toss all the old list items */ + while ( (temp = sp_repr_children( parent )) ) { + parent->removeChild(temp); + } + + /* chop our list up on commas */ + strlist = g_strsplit( text, ",", 0); + + for (i = 0; (str = strlist[i]); i++) { + temp = xmldoc->createElement ( "rdf:li" ); + g_return_val_if_fail (temp != NULL, 0); + + parent->appendChild(temp); + Inkscape::GC::release(temp); + + child = xmldoc->createTextNode( g_strstrip(str) ); + g_return_val_if_fail (child != NULL, 0); + + temp->appendChild(child); + Inkscape::GC::release(child); + } + g_strfreev( strlist ); + + return 1; + + default: + break; + } + return 0; +} + +Inkscape::XML::Node * +rdf_get_rdf_root_repr ( SPDocument * doc, bool build ) +{ + g_return_val_if_fail (doc != NULL, NULL); + g_return_val_if_fail (doc->rroot != NULL, NULL); + + Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); + g_return_val_if_fail (xmldoc != NULL, NULL); + + Inkscape::XML::Node * rdf = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_RDF ); + + if (rdf == NULL) { + //printf("missing XML '%s'\n",XML_TAG_NAME_RDF); + if (!build) return NULL; + + Inkscape::XML::Node * svg = sp_repr_lookup_name ( doc->rroot, XML_TAG_NAME_SVG ); + g_return_val_if_fail ( svg != NULL, NULL ); + + Inkscape::XML::Node * parent = sp_repr_lookup_name ( svg, XML_TAG_NAME_METADATA ); + if ( parent == NULL ) { + parent = xmldoc->createElement( XML_TAG_NAME_METADATA ); + g_return_val_if_fail ( parent != NULL, NULL); + + svg->appendChild(parent); + Inkscape::GC::release(parent); + } + + Inkscape::XML::Document * xmldoc = parent->document(); + g_return_val_if_fail (xmldoc != NULL, FALSE); + + rdf = xmldoc->createElement( XML_TAG_NAME_RDF ); + g_return_val_if_fail (rdf != NULL, NULL); + + parent->appendChild(rdf); + Inkscape::GC::release(rdf); + } + + /* + * some implementations do not put RDF stuff inside <metadata>, + * so we need to check for it and add it if we don't see it + */ + Inkscape::XML::Node * want_metadata = sp_repr_parent ( rdf ); + g_return_val_if_fail (want_metadata != NULL, NULL); + if (strcmp( want_metadata->name(), XML_TAG_NAME_METADATA )) { + Inkscape::XML::Node * metadata = xmldoc->createElement( XML_TAG_NAME_METADATA ); + g_return_val_if_fail (metadata != NULL, NULL); + + /* attach the metadata node */ + want_metadata->appendChild(metadata); + Inkscape::GC::release(metadata); + + /* move the RDF into it */ + Inkscape::GC::anchor(rdf); + sp_repr_unparent ( rdf ); + metadata->appendChild(rdf); + Inkscape::GC::release(rdf); + } + + return rdf; +} + +Inkscape::XML::Node * +rdf_get_xml_repr( SPDocument * doc, gchar const * name, bool build ) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (doc != NULL, NULL); + g_return_val_if_fail (doc->rroot != NULL, NULL); + + Inkscape::XML::Node * rdf = rdf_get_rdf_root_repr ( doc, build ); + if (!rdf) return NULL; + + Inkscape::XML::Node * xml = sp_repr_lookup_name ( rdf, name ); + if (xml == NULL) { + //printf("missing XML '%s'\n",name); + if (!build) return NULL; + + Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); + g_return_val_if_fail (xmldoc != NULL, NULL); + + xml = xmldoc->createElement( name ); + g_return_val_if_fail (xml != NULL, NULL); + + xml->setAttribute("rdf:about", "" ); + + rdf->appendChild(xml); + Inkscape::GC::release(xml); + } + + return xml; +} + +Inkscape::XML::Node * +rdf_get_work_repr( SPDocument * doc, gchar const * name, bool build ) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (doc != NULL, NULL); + g_return_val_if_fail (doc->rroot != NULL, NULL); + + Inkscape::XML::Node * work = rdf_get_xml_repr ( doc, XML_TAG_NAME_WORK, build ); + if (!work) return NULL; + + Inkscape::XML::Node * item = sp_repr_lookup_name ( work, name, 1 ); + if (item == NULL) { + //printf("missing XML '%s'\n",name); + if (!build) return NULL; + + Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); + g_return_val_if_fail (xmldoc != NULL, NULL); + + item = xmldoc->createElement( name ); + g_return_val_if_fail (item != NULL, NULL); + + work->appendChild(item); + Inkscape::GC::release(item); + } + + return item; +} + + + +/** + * \brief Retrieves a known RDF/Work entity's contents from the document XML by name + * \return A pointer to the entity's static contents as a string, or NULL if no entity exists + * \param entity The desired RDF/Work entity + * + */ +const gchar * +rdf_get_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity) +{ + g_return_val_if_fail (doc != NULL, NULL); + if ( entity == NULL ) return NULL; + //printf("want '%s'\n",entity->title); + bool bIsTitle = !strcmp(entity->name, "title"); + + Inkscape::XML::Node * item; + if ( entity->datatype == RDF_XML ) { + item = rdf_get_xml_repr ( doc, entity->tag, FALSE ); + } + else { + item = rdf_get_work_repr( doc, entity->tag, bIsTitle ); // build title if necessary + } + if ( item == NULL ) return NULL; + const gchar * result = rdf_get_repr_text ( item, entity ); + if(!result && bIsTitle && doc->root) { // if RDF title not set + result = doc->root->title(); // get the document's <title> + rdf_set_work_entity(doc, entity, result); // and set the RDF + } + //printf("found '%s' == '%s'\n", entity->title, result ); + return result; +} + +/** + * \brief Stores a string into a named RDF/Work entity in the document XML + * \param entity The desired RDF/Work entity to replace + * \param string The string to replace the entity contents with + * + */ +unsigned int +rdf_set_work_entity(SPDocument * doc, struct rdf_work_entity_t * entity, + const gchar * text) +{ + g_return_val_if_fail ( entity != NULL, 0 ); + if (text == NULL) { + // FIXME: on a "NULL" text, delete the entity. For now, blank it. + text=""; + } + + /* + printf("changing '%s' (%s) to '%s'\n", + entity->title, + entity->tag, + text); + */ + + Inkscape::XML::Node * item = rdf_get_work_repr( doc, entity->tag, TRUE ); + g_return_val_if_fail ( item != NULL, 0 ); + + return rdf_set_repr_text ( item, entity, text ); +} + +#undef DEBUG_MATCH + +static bool +rdf_match_license(Inkscape::XML::Node const *repr, struct rdf_license_t const *license) +{ + g_assert ( repr != NULL ); + g_assert ( license != NULL ); + + bool result=TRUE; +#ifdef DEBUG_MATCH + printf("checking against '%s'\n",license->name); +#endif + + int count = 0; + for (struct rdf_double_t const *details = license->details; + details->name; details++ ) { + count++; + } + bool * matched = (bool*)calloc(count,sizeof(bool)); + + for (Inkscape::XML::Node const *current = sp_repr_children(repr); + current; + current = sp_repr_next ( current ) ) { + + gchar const * attr = current->attribute("rdf:resource"); + if ( attr == NULL ) continue; + +#ifdef DEBUG_MATCH + printf("\texamining '%s' => '%s'\n", current->name(), attr); +#endif + + bool found_match=FALSE; + for (int i=0; i<count; i++) { + // skip already matched items + if (matched[i]) continue; + +#ifdef DEBUG_MATCH + printf("\t\t'%s' vs '%s'\n", current->name(), license->details[i].name); + printf("\t\t'%s' vs '%s'\n", attr, license->details[i].resource); +#endif + + if (!strcmp( current->name(), + license->details[i].name ) && + !strcmp( attr, + license->details[i].resource )) { + matched[i]=TRUE; + found_match=TRUE; +#ifdef DEBUG_MATCH + printf("\t\tgood!\n"); +#endif + break; + } + } + if (!found_match) { + // if we checked each known item of the license + // and didn't find it, we must abort + result=FALSE; +#ifdef DEBUG_MATCH + printf("\t\tno '%s' element matched XML (bong)!\n",license->name); +#endif + break; + } + } +#ifdef DEBUG_MATCH + if (result) printf("\t\tall XML found matching elements!\n"); +#endif + for (int i=0; result && i<count; i++) { + // scan looking for an unmatched item + if (matched[i]==0) { + result=FALSE; +#ifdef DEBUG_MATCH + printf("\t\tnot all '%s' elements used to match (bong)!\n", license->name); +#endif + } + } + +#ifdef DEBUG_MATCH + printf("\t\tall '%s' elements used to match!\n",license->name); +#endif + + free(matched); + +#ifdef DEBUG_MATCH + if (result) printf("matched '%s'\n",license->name); +#endif + return result; +} + +/** + * \brief Attempts to match and retrieve a known RDF/License from the document XML + * \return A pointer to the static RDF license structure + * + */ +struct rdf_license_t * +rdf_get_license(SPDocument * document) +{ + Inkscape::XML::Node const *repr = rdf_get_xml_repr ( document, XML_TAG_NAME_LICENSE, FALSE ); + if (repr) { + for (struct rdf_license_t * license = rdf_licenses; + license->name; license++ ) { + if ( rdf_match_license ( repr, license ) ) return license; + } + } +#ifdef DEBUG_MATCH + else { + printf("no license XML\n"); + } +#endif + return NULL; +} + +/** + * \brief Stores an RDF/License XML in the document XML + * \param document Which document to update + * \param license The desired RDF/License structure to store; NULL drops old license, so can be used for proprietary license. + * + */ +void +rdf_set_license(SPDocument * doc, struct rdf_license_t const * license) +{ + // drop old license section + Inkscape::XML::Node * repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, FALSE ); + if (repr) sp_repr_unparent(repr); + + if (!license) return; + + // build new license section + repr = rdf_get_xml_repr ( doc, XML_TAG_NAME_LICENSE, TRUE ); + g_assert ( repr ); + + repr->setAttribute("rdf:about", license->uri ); + + Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); + g_return_if_fail (xmldoc != NULL); + + for (struct rdf_double_t const * detail = license->details; + detail->name; detail++) { + Inkscape::XML::Node * child = xmldoc->createElement( detail->name ); + g_assert ( child != NULL ); + + child->setAttribute("rdf:resource", detail->resource ); + repr->appendChild(child); + Inkscape::GC::release(child); + } +} + +struct rdf_entity_default_t { + gchar const * name; + gchar const * text; +}; +struct rdf_entity_default_t rdf_defaults[] = { + { "format", "image/svg+xml", }, + { "type", "http://purl.org/dc/dcmitype/StillImage", }, + { NULL, NULL, } +}; + +void +rdf_set_defaults ( SPDocument * doc ) +{ + g_assert ( doc != NULL ); + + // Create metadata node if it doesn't already exist + if (!sp_item_group_get_child_by_name ((SPGroup *) doc->root, NULL, + XML_TAG_NAME_METADATA)) { + // create repr + Inkscape::XML::Document * xmldoc = sp_document_repr_doc(doc); + g_return_if_fail (xmldoc != NULL); + Inkscape::XML::Node * rnew = xmldoc->createElement (XML_TAG_NAME_METADATA); + // insert into the document + doc->rroot->addChild(rnew, NULL); + // clean up + Inkscape::GC::release(rnew); + } + + /* install defaults */ + for ( struct rdf_entity_default_t * rdf_default = rdf_defaults; + rdf_default->name; + rdf_default++) { + struct rdf_work_entity_t * entity = rdf_find_entity ( rdf_default->name ); + g_assert ( entity != NULL ); + + if ( rdf_get_work_entity ( doc, entity ) == NULL ) { + rdf_set_work_entity ( doc, entity, rdf_default->text ); + } + } +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/rdf.h b/src/rdf.h new file mode 100644 index 000000000..a98f5a1e4 --- /dev/null +++ b/src/rdf.h @@ -0,0 +1,120 @@ +/** @file + * @brief headers for RDF types + */ +/* Authors: + * Kees Cook <kees@outflux.net> + * + * Copyright (C) 2004 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef _RDF_H_ +#define _RDF_H_ + +#include <glib.h> +#include <glibmm/i18n.h> +#include "document.h" + +// yeah, it's not a triple yet... +/** + * \brief Holds license name/resource doubles for rdf_license_t entries + */ +struct rdf_double_t { + gchar const *name; + gchar const *resource; +}; + +/** + * \brief Holds license name and RDF information + */ +struct rdf_license_t { + gchar const *name; /* localized name of this license */ + gchar const *uri; /* URL for the RDF/Work/license element */ + struct rdf_double_t *details; /* the license details */ +// gchar const *fragment; /* XML contents for the RDF/License tag */ +}; + +extern rdf_license_t rdf_licenses []; + +/** + * \brief Describes how a given RDF entity is stored in XML + */ +enum RDFType { + RDF_CONTENT, // direct between-XML-tags content + RDF_AGENT, // requires the "Agent" hierarchy before doing content + RDF_RESOURCE, // stored in "rdf:resource" element + RDF_XML, // literal XML + RDF_BAG // rdf:Bag resources +}; + +/** + * \brief Describes how a given RDF entity should be edited + */ +enum RDF_Format { + RDF_FORMAT_LINE, // uses single line data (GtkEntry) + RDF_FORMAT_MULTILINE, // uses multiline data (GtkTextView) + RDF_FORMAT_SPECIAL // uses some other edit methods +}; + +enum RDF_Editable { + RDF_EDIT_GENERIC, // editable via generic widgets + RDF_EDIT_SPECIAL, // special widgets are needed + RDF_EDIT_HARDCODED // isn't editable +}; + +/** + * \brief Holds known RDF/Work tags + */ +struct rdf_work_entity_t { + char const *name; /* unique name of this entity for internal reference */ + gchar const *title; /* localized title of this entity for data entry */ + gchar const *tag; /* namespace tag for the RDF/Work element */ + RDFType datatype; /* how to extract/inject the RDF information */ + gchar const *tip; /* tool tip to explain the meaning of the entity */ + RDF_Format format; /* in what format is this data edited? */ + RDF_Editable editable;/* in what way is the data editable? */ +}; + +extern rdf_work_entity_t rdf_work_entities []; + +/** + * \brief Generic collection of RDF information for the RDF debug function + */ +struct rdf_t { + gchar* work_title; + gchar* work_date; + gchar* work_creator; + gchar* work_owner; + gchar* work_publisher; + gchar* work_type; + gchar* work_source; + gchar* work_subject; + gchar* work_description; + struct rdf_license_t* license; +}; + +struct rdf_work_entity_t * rdf_find_entity(gchar const * name); + +const gchar * rdf_get_work_entity(SPDocument * doc, + struct rdf_work_entity_t * entity); +unsigned int rdf_set_work_entity(SPDocument * doc, + struct rdf_work_entity_t * entity, + const gchar * text); + +struct rdf_license_t * rdf_get_license(SPDocument * doc); +void rdf_set_license(SPDocument * doc, + struct rdf_license_t const * license); + +void rdf_set_defaults ( SPDocument * doc ); + +#endif // _RDF_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/Makefile_insert b/src/ui/Makefile_insert index e91c22025..3eb6c6b13 100644 --- a/src/ui/Makefile_insert +++ b/src/ui/Makefile_insert @@ -1,9 +1,11 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ - ui/clipboard.cpp \ - ui/clipboard.h \ - ui/icon-names.h \ + ui/context-menu.cpp \ + ui/context-menu.h \ + ui/clipboard.cpp \ + ui/clipboard.h \ + ui/icon-names.h \ ui/previewable.h \ ui/previewfillable.h \ ui/previewholder.cpp \ diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index bf3b6baeb..6a9ebf61f 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -1,11 +1,23 @@ ## Makefile.am fragment sourced by src/Makefile.am. +if WITH_INKBOARD +inkboard_dialogs = \ + whiteboard-connect.cpp \ + whiteboard-connect.h \ + whiteboard-sharewithchat.cpp \ + whiteboard-sharewithchat.h \ + whiteboard-sharewithuser.cpp \ + whiteboard-sharewithuser.h +endif + ink_common_sources += \ ui/dialog/aboutbox.cpp \ ui/dialog/aboutbox.h \ ui/dialog/align-and-distribute.cpp \ ui/dialog/align-and-distribute.h \ ui/dialog/behavior.h \ + ui/dialog/calligraphic-profile-rename.h \ + ui/dialog/calligraphic-profile-rename.cpp \ ui/dialog/debug.cpp \ ui/dialog/debug.h \ ui/dialog/dialog.cpp \ @@ -20,6 +32,8 @@ ink_common_sources += \ ui/dialog/document-properties.h \ ui/dialog/extension-editor.cpp \ ui/dialog/extension-editor.h \ + ui/dialog/extensions.cpp \ + ui/dialog/extensions.h \ ui/dialog/filedialog.cpp \ ui/dialog/filedialog.h \ ui/dialog/filedialogimpl-gtkmm.cpp \ @@ -34,10 +48,18 @@ ink_common_sources += \ ui/dialog/find.h \ ui/dialog/floating-behavior.cpp \ ui/dialog/floating-behavior.h \ + ui/dialog/guides.cpp \ + ui/dialog/guides.h \ + ui/dialog/icon-preview.cpp \ + ui/dialog/icon-preview.h \ ui/dialog/inkscape-preferences.cpp \ ui/dialog/inkscape-preferences.h \ ui/dialog/input.cpp \ ui/dialog/input.h \ + ui/dialog/layer-properties.cpp \ + ui/dialog/layer-properties.h \ + ui/dialog/layers.cpp \ + ui/dialog/layers.h \ ui/dialog/livepatheffect-editor.cpp \ ui/dialog/livepatheffect-editor.h \ ui/dialog/memory.cpp \ @@ -53,6 +75,8 @@ ink_common_sources += \ ui/dialog/scriptdialog.h \ ui/dialog/svg-fonts-dialog.cpp \ ui/dialog/svg-fonts-dialog.h \ + ui/dialog/swatches.cpp \ + ui/dialog/swatches.h \ ui/dialog/tile.cpp \ ui/dialog/tile.h \ ui/dialog/tracedialog.cpp \ diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 0a59c004f..d8c4bc005 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -21,7 +21,7 @@ #include <gtkmm/spinbutton.h> #include "desktop-handles.h" -#include "dialogs/unclump.h" +#include "unclump.h" #include "document.h" #include "enums.h" #include "graphlayout/graphlayout.h" diff --git a/src/ui/dialog/calligraphic-profile-rename.cpp b/src/ui/dialog/calligraphic-profile-rename.cpp new file mode 100644 index 000000000..888b327f4 --- /dev/null +++ b/src/ui/dialog/calligraphic-profile-rename.cpp @@ -0,0 +1,108 @@ +/** @file + * @brief Dialog for naming calligraphic profiles + * + * @note This file is in the wrong directory because of link order issues - + * it is required by widgets/toolbox.cpp, and libspwidgets.a comes after + * libinkdialogs.a in the current link order. + */ +/* Author: + * Aubanel MONNIER + * + * Copyright (C) 2007 Authors + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glibmm/i18n.h> +#include <gtkmm/stock.h> + +#include "desktop.h" +#include "calligraphic-profile-rename.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +CalligraphicProfileRename::CalligraphicProfileRename() : + _applied(false) +{ + Gtk::VBox *mainVBox = get_vbox(); + _layout_table.set_spacings(4); + _layout_table.resize (1, 2); + + _profile_name_entry.set_activates_default(true); + + _profile_name_label.set_label(_("Profile name:")); + _profile_name_label.set_alignment(1.0, 0.5); + + _layout_table.attach(_profile_name_label, + 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + _layout_table.attach(_profile_name_entry, + 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + mainVBox->pack_start(_layout_table, false, false, 4); + // Buttons + _close_button.set_use_stock(true); + _close_button.set_label(Gtk::Stock::CANCEL.id); + _close_button.set_flags(Gtk::CAN_DEFAULT); + + _apply_button.set_use_underline(true); + _apply_button.set_label(_("Save")); + _apply_button.set_flags(Gtk::CAN_DEFAULT); + + _close_button.signal_clicked() + .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)); + _apply_button.signal_clicked() + .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_apply)); + + signal_delete_event().connect( sigc::bind_return( + sigc::hide(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)), true ) ); + + add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); + add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); + + _apply_button.grab_default(); + + show_all_children(); +} + +void CalligraphicProfileRename::_apply() +{ + _profile_name = _profile_name_entry.get_text(); + _applied = true; + _close(); +} + +void CalligraphicProfileRename::_close() +{ + this->Gtk::Dialog::hide(); +} + +void CalligraphicProfileRename::show(SPDesktop *desktop) +{ + CalligraphicProfileRename &dial = instance(); + dial._applied=false; + dial.set_modal(true); + desktop->setWindowTransient (dial.gobj()); + dial.property_destroy_with_parent() = true; + // dial.Gtk::Dialog::show(); + //dial.present(); + dial.run(); +} + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/calligraphic-profile-rename.h b/src/ui/dialog/calligraphic-profile-rename.h new file mode 100644 index 000000000..53ce907ed --- /dev/null +++ b/src/ui/dialog/calligraphic-profile-rename.h @@ -0,0 +1,75 @@ +/** @file + * @brief Dialog for naming calligraphic profiles + */ +/* Author: + * Aubanel MONNIER + * + * Copyright (C) 2007 Authors + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H +#define INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H + +#include <gtkmm/dialog.h> +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/table.h> +struct SPDesktop; + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class CalligraphicProfileRename : public Gtk::Dialog { +public: + CalligraphicProfileRename(); + virtual ~CalligraphicProfileRename() {} + Glib::ustring getName() const { + return "CalligraphicProfileRename"; + } + + static void show(SPDesktop *desktop); + static bool applied() { + return instance()._applied; + } + static Glib::ustring getProfileName() { + return instance()._profile_name; + } + +protected: + void _close(); + void _apply(); + + Gtk::Label _profile_name_label; + Gtk::Entry _profile_name_entry; + Gtk::Table _layout_table; + Gtk::Button _close_button; + Gtk::Button _apply_button; + Glib::ustring _profile_name; + bool _applied; +private: + static CalligraphicProfileRename &instance() { + static CalligraphicProfileRename instance_; + return instance_; + } + CalligraphicProfileRename(CalligraphicProfileRename const &); // no copy + CalligraphicProfileRename &operator=(CalligraphicProfileRename const &); // no assign +}; + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 7a8947adf..d1b818d23 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -31,22 +31,21 @@ #include "ui/dialog/memory.h" #include "ui/dialog/messages.h" #include "ui/dialog/scriptdialog.h" -#ifdef ENABLE_SVG_FONTS -#include "ui/dialog/svg-fonts-dialog.h" -#endif // ENABLE_SVG_FONTS #include "ui/dialog/tile.h" #include "ui/dialog/tracedialog.h" #include "ui/dialog/transformation.h" #include "ui/dialog/undo-history.h" #include "ui/dialog/panel-dialog.h" - -#include "dialogs/layers-panel.h" -#include "dialogs/iconpreview.h" - +#include "ui/dialog/layers.h" +#include "ui/dialog/icon-preview.h" #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" #include "preferences.h" +#ifdef ENABLE_SVG_FONTS +#include "ui/dialog/svg-fonts-dialog.h" +#endif // ENABLE_SVG_FONTS + namespace Inkscape { namespace UI { namespace Dialog { diff --git a/src/ui/dialog/document-metadata.cpp b/src/ui/dialog/document-metadata.cpp index 32838309a..96cad1fbe 100644 --- a/src/ui/dialog/document-metadata.cpp +++ b/src/ui/dialog/document-metadata.cpp @@ -17,18 +17,14 @@ # include <config.h> #endif - - -#include "ui/widget/entity-entry.h" - -#include "xml/node-event-vector.h" -#include "dialogs/rdf.h" - -#include "inkscape.h" -#include "verbs.h" -#include "desktop-handles.h" #include "desktop.h" +#include "desktop-handles.h" +#include "inkscape.h" +#include "rdf.h" #include "sp-namedview.h" +#include "ui/widget/entity-entry.h" +#include "verbs.h" +#include "xml/node-event-vector.h" #include "document-metadata.h" diff --git a/src/ui/dialog/extensions.cpp b/src/ui/dialog/extensions.cpp new file mode 100644 index 000000000..f168da33a --- /dev/null +++ b/src/ui/dialog/extensions.cpp @@ -0,0 +1,129 @@ +/** @file + * @brief A simple dialog with information about extensions + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types +#include <gtkmm/scrolledwindow.h> + +#include "extension/db.h" +#include "extensions.h" + + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +using Inkscape::Extension::Extension; + +ExtensionsPanel &ExtensionsPanel::getInstance() +{ + ExtensionsPanel &instance = *new ExtensionsPanel(); + + instance.rescan(); + + return instance; +} + + + +/** + * Constructor + */ +ExtensionsPanel::ExtensionsPanel() : + _showAll(false) +{ + Gtk::ScrolledWindow* scroller = new Gtk::ScrolledWindow(); + + _view.set_editable(false); + + scroller->add(_view); + add(*scroller); + + rescan(); + + show_all_children(); +} + +void ExtensionsPanel::set_full(bool full) +{ + if ( full != _showAll ) { + _showAll = full; + rescan(); + } +} + +void ExtensionsPanel::listCB( Inkscape::Extension::Extension * in_plug, gpointer in_data ) +{ + ExtensionsPanel * self = (ExtensionsPanel*)in_data; + + const char* stateStr; + Extension::state_t state = in_plug->get_state(); + switch ( state ) { + case Extension::STATE_LOADED: + { + stateStr = "loaded"; + } + break; + case Extension::STATE_UNLOADED: + { + stateStr = "unloaded"; + } + break; + case Extension::STATE_DEACTIVATED: + { + stateStr = "deactivated"; + } + break; + default: + stateStr = "unknown"; + } + + if ( self->_showAll || in_plug->deactivated() ) { +// gchar* line = g_strdup_printf( " extension %c %c %s |%s|%s|", +// (in_plug->loaded() ? 'X' : '-'), +// (in_plug->deactivated() ? 'X' : '-'), +// stateStr, in_plug->get_id(), +// in_plug->get_name() ); + gchar* line = g_strdup_printf( "%s %s\n \"%s\"", stateStr, in_plug->get_name(), in_plug->get_id() ); + + self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), line ); + self->_view.get_buffer()->insert( self->_view.get_buffer()->end(), "\n" ); + //g_message( "%s", line ); + } + + + + return; +} + +void ExtensionsPanel::rescan() +{ + _view.get_buffer()->set_text("Extensions:\n"); +// g_message("/------------------"); + + Inkscape::Extension::db.foreach(listCB, (gpointer)this); + +// g_message("\\------------------"); +} + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/extensions.h b/src/ui/dialog/extensions.h new file mode 100644 index 000000000..8b0fc2780 --- /dev/null +++ b/src/ui/dialog/extensions.h @@ -0,0 +1,56 @@ +/** @file + * A simple dialog with information about extensions + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 The Inkscape Organization + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_EXTENSIONS_H +#define SEEN_EXTENSIONS_H + +#include <gtkmm/textview.h> +#include "ui/widget/panel.h" + +namespace Inkscape { +namespace Extension { +class Extension; +} +} + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays information about extensions. + */ +class ExtensionsPanel : public Inkscape::UI::Widget::Panel +{ +public: + ExtensionsPanel(); + + static ExtensionsPanel &getInstance(); + + void set_full(bool full); + +private: + ExtensionsPanel(ExtensionsPanel const &); // no copy + ExtensionsPanel &operator=(ExtensionsPanel const &); // no assign + + static void listCB(Inkscape::Extension::Extension *in_plug, gpointer in_data); + + void rescan(); + + bool _showAll; + Gtk::TextView _view; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +#endif // SEEN_EXTENSIONS_H diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index d28dc7955..fe63c6e24 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -21,15 +21,13 @@ #include "selection.h" #include "style.h" #include "svg/css-ostringstream.h" +#include "ui/icon-names.h" #include "verbs.h" -#include "xml/repr.h" +#include "widgets/fill-style.h" #include "widgets/icon.h" -#include "ui/icon-names.h" - -#include "dialogs/fill-style.h" -#include "dialogs/stroke-style.h" - -#include <widgets/paint-selector.h> +#include "widgets/paint-selector.h" +#include "widgets/stroke-style.h" +#include "xml/repr.h" namespace Inkscape { namespace UI { diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp new file mode 100644 index 000000000..c5d2ae488 --- /dev/null +++ b/src/ui/dialog/guides.cpp @@ -0,0 +1,285 @@ +/** @file + * @brief Simple guideline dialog + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Andrius R. <knutux@gmail.com> + * Johan Engelen + * + * Copyright (C) 1999-2007 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "display/guideline.h" +#include "helper/unit-menu.h" +#include "helper/units.h" +#include "desktop.h" +#include "document.h" +#include "sp-guide.h" +#include "sp-namedview.h" +#include "desktop-handles.h" +#include "event-context.h" +#include "widgets/desktop-widget.h" +#include "sp-metrics.h" +#include <glibmm/i18n.h> +#include "dialogs/dialog-events.h" +#include "message-context.h" +#include "xml/repr.h" +#include <2geom/point.h> +#include <2geom/angle.h> +#include "guides.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +GuidelinePropertiesDialog::GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop) +: _desktop(desktop), _guide(guide), + _label_units(_("Unit:")), + _label_X(_("X:")), + _label_Y(_("Y:")), + _label_degrees(_("Angle (degrees):")), + _relative_toggle(_("Rela_tive change"), _("Move and/or rotate the guide relative to current settings")), + _adjustment_x(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), + _adjustment_y(0.0, -1e6, 1e6, 1.0, 10.0, 10.0), + _adj_angle(0.0, -360, 360, 1.0, 10.0, 10.0), + _unit_selector(NULL), _mode(true), _oldpos(0.,0.), _oldangle(0.0) +{ +} + +GuidelinePropertiesDialog::~GuidelinePropertiesDialog() { +} + +void GuidelinePropertiesDialog::showDialog(SPGuide *guide, SPDesktop *desktop) { + GuidelinePropertiesDialog dialog(guide, desktop); + dialog._setup(); + dialog.run(); +} + +void GuidelinePropertiesDialog::_modeChanged() +{ + _mode = !_relative_toggle.get_active(); + if (!_mode) { + // relative + _spin_angle.set_value(0); + + _spin_button_y.set_value(0); + _spin_button_x.set_value(0); + } else { + // absolute + _spin_angle.set_value(_oldangle); + + SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); + gdouble const val_y = sp_pixels_get_units(_oldpos[Geom::Y], unit); + _spin_button_y.set_value(val_y); + gdouble const val_x = sp_pixels_get_units(_oldpos[Geom::X], unit); + _spin_button_x.set_value(val_x); + } +} + +void GuidelinePropertiesDialog::_onApply() +{ + double deg_angle = _spin_angle.get_value(); + if (!_mode) + deg_angle += _oldangle; + Geom::Point normal; + if ( deg_angle == 90. || deg_angle == 270. || deg_angle == -90. || deg_angle == -270.) { + normal = Geom::Point(1.,0.); + } else if ( deg_angle == 0. || deg_angle == 180. || deg_angle == -180.) { + normal = Geom::Point(0.,1.); + } else { + double rad_angle = Geom::deg_to_rad( deg_angle ); + normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0)); + } + sp_guide_set_normal(*_guide, normal, true); + + SPUnit const &unit = *sp_unit_selector_get_unit(SP_UNIT_SELECTOR(_unit_selector->gobj())); + gdouble const raw_dist_x = _spin_button_x.get_value(); + gdouble const points_x = sp_units_get_pixels(raw_dist_x, unit); + gdouble const raw_dist_y = _spin_button_y.get_value(); + gdouble const points_y = sp_units_get_pixels(raw_dist_y, unit); + Geom::Point newpos(points_x, points_y); + if (!_mode) + newpos += _oldpos; + + sp_guide_moveto(*_guide, newpos, true); + + sp_document_done(SP_OBJECT_DOCUMENT(_guide), SP_VERB_NONE, + _("Set guide properties")); +} + +void GuidelinePropertiesDialog::_onOK() +{ + _onApply(); +} + +void GuidelinePropertiesDialog::_onDelete() +{ + SPDocument *doc = SP_OBJECT_DOCUMENT(_guide); + sp_guide_remove(_guide); + sp_document_done(doc, SP_VERB_NONE, + _("Delete guide")); +} + +void GuidelinePropertiesDialog::_response(gint response) +{ + switch (response) { + case Gtk::RESPONSE_OK: + _onOK(); + break; + case -12: + _onDelete(); + break; + case Gtk::RESPONSE_CANCEL: + break; + case Gtk::RESPONSE_DELETE_EVENT: + break; +/* case GTK_RESPONSE_APPLY: + _onApply(); + break; +*/ + default: + g_assert_not_reached(); + } +} + +void GuidelinePropertiesDialog::_setup() { + set_title(_("Guideline")); + add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + add_button(Gtk::Stock::DELETE, -12); + add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + Gtk::VBox *mainVBox = get_vbox(); + + _layout_table.set_spacings(4); + _layout_table.resize (3, 4); + + mainVBox->pack_start(_layout_table, false, false, 0); + + _label_name.set_label("foo0"); + _layout_table.attach(_label_name, + 0, 3, 0, 1, Gtk::FILL, Gtk::FILL); + _label_name.set_alignment(0, 0.5); + + _label_descr.set_label("foo1"); + _layout_table.attach(_label_descr, + 0, 3, 1, 2, Gtk::FILL, Gtk::FILL); + _label_descr.set_alignment(0, 0.5); + + // indent + _layout_table.attach(*manage(new Gtk::Label(" ")), + 0, 1, 2, 3, Gtk::FILL, Gtk::FILL, 10); + + // mode radio button + _layout_table.attach(_relative_toggle, + 1, 3, 9, 10, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _relative_toggle.signal_toggled().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_modeChanged)); + + // unitmenu + /* fixme: We should allow percents here too, as percents of the canvas size */ + GtkWidget *unit_selector = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); + sp_unit_selector_set_unit(SP_UNIT_SELECTOR(unit_selector), _desktop->namedview->doc_units); + _unit_selector = Gtk::manage(Glib::wrap(unit_selector)); + + // position spinbuttons + sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_x.gobj())); + sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(unit_selector), GTK_ADJUSTMENT(_adjustment_y.gobj())); + _spin_button_x.configure(_adjustment_x, 1.0 , 3); + _spin_button_x.set_numeric(); + _spin_button_y.configure(_adjustment_y, 1.0 , 3); + _spin_button_y.set_numeric(); + _layout_table.attach(_label_X, + 1, 2, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_button_x, + 2, 3, 4, 5, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_label_Y, + 1, 2, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_button_y, + 2, 3, 5, 6, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + gtk_signal_connect_object(GTK_OBJECT(_spin_button_x.gobj()), "activate", + GTK_SIGNAL_FUNC(gtk_window_activate_default), + gobj()); + + _layout_table.attach(_label_units, + 1, 2, 6, 7, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(*_unit_selector, + 2, 3, 6, 7, Gtk::FILL, Gtk::FILL); + + // angle spinbutton + _spin_angle.configure(_adj_angle, 5.0 , 3); + _spin_angle.set_numeric(); + _spin_angle.show(); + _layout_table.attach(_label_degrees, + 1, 2, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + _layout_table.attach(_spin_angle, + 2, 3, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + + + // dialog + set_default_response(Gtk::RESPONSE_OK); + signal_response().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_response)); + + // initialize dialog + _oldpos = _guide->point_on_line; + if (_guide->is_vertical()) { + _oldangle = 90; + } else if (_guide->is_horizontal()) { + _oldangle = 0; + } else { + _oldangle = Geom::rad_to_deg( std::atan2( - _guide->normal_to_line[Geom::X], _guide->normal_to_line[Geom::Y] ) ); + } + + { + Inkscape::XML::Node *repr = SP_OBJECT_REPR (_guide); + const gchar *guide_id = repr->attribute("id"); + gchar *label = g_strdup_printf(_("Guideline ID: %s"), guide_id); + _label_name.set_label(label); + g_free(label); + } + { + gchar *guide_description = sp_guide_description(_guide); + gchar *label = g_strdup_printf(_("Current: %s"), guide_description); + g_free(guide_description); + _label_descr.set_markup(label); + g_free(label); + } + + _modeChanged(); // sets values of spinboxes. + + if ( _oldangle == 90. || _oldangle == 270. || _oldangle == -90. || _oldangle == -270.) { + _spin_button_x.grab_focus(); + _spin_button_x.select_region(0, 20); + } else if ( _oldangle == 0. || _oldangle == 180. || _oldangle == -180.) { + _spin_button_y.grab_focus(); + _spin_button_y.select_region(0, 20); + } else { + _spin_angle.grab_focus(); + _spin_angle.select_region(0, 20); + } + + set_position(Gtk::WIN_POS_MOUSE); + + show_all_children(); + set_modal(true); + _desktop->setWindowTransient (gobj()); + property_destroy_with_parent() = true; +} + +} +} +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/guides.h b/src/ui/dialog/guides.h new file mode 100644 index 000000000..49f94deea --- /dev/null +++ b/src/ui/dialog/guides.h @@ -0,0 +1,93 @@ +/** + * + * \brief Dialog for modifying guidelines + * + * Author: + * Andrius R. <knutux@gmail.com> + * Johan Engelen + * + * Copyright (C) 2006-2007 Authors + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_GUIDELINE_H +#define INKSCAPE_DIALOG_GUIDELINE_H + +#include <gtkmm/dialog.h> +#include <gtkmm/table.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/label.h> +#include <gtkmm/stock.h> +#include <gtkmm/adjustment.h> +#include "ui/widget/button.h" +#include <2geom/point.h> + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +class GuidelinePropertiesDialog : public Gtk::Dialog { +public: + GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop); + virtual ~GuidelinePropertiesDialog(); + + Glib::ustring getName() const { return "GuidelinePropertiesDialog"; } + + static void showDialog(SPGuide *guide, SPDesktop *desktop); + +protected: + void _setup(); + + void _onApply(); + void _onOK(); + void _onDelete(); + + void _response(gint response); + void _modeChanged(); + +private: + GuidelinePropertiesDialog(GuidelinePropertiesDialog const &); // no copy + GuidelinePropertiesDialog &operator=(GuidelinePropertiesDialog const &); // no assign + + SPDesktop *_desktop; + SPGuide *_guide; + Gtk::Table _layout_table; + Gtk::Label _label_name; + Gtk::Label _label_descr; + Gtk::Label _label_units; + Gtk::Label _label_X; + Gtk::Label _label_Y; + Gtk::Label _label_degrees; + Inkscape::UI::Widget::CheckButton _relative_toggle; + Gtk::Adjustment _adjustment_x; + Gtk::SpinButton _spin_button_x; + Gtk::Adjustment _adjustment_y; + Gtk::SpinButton _spin_button_y; + + Gtk::Adjustment _adj_angle; + Gtk::SpinButton _spin_angle; + + Gtk::Widget *_unit_selector; + bool _mode; + Geom::Point _oldpos; + gdouble _oldangle; +}; + +} // namespace +} // namespace +} // namespace + + +#endif // INKSCAPE_DIALOG_GUIDELINE_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp new file mode 100644 index 000000000..336afc3c5 --- /dev/null +++ b/src/ui/dialog/icon-preview.cpp @@ -0,0 +1,307 @@ +/** @file + * @brief A simple dialog for previewing icon representation. + */ +/* Authors: + * Jon A. Cruz + * Bob Jamison + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004 Bob Jamison + * Copyright (C) 2005 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glib/gmem.h> +#include <glibmm/i18n.h> +#include <gtkmm/buttonbox.h> +#include <gtkmm/stock.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "display/nr-arena.h" +#include "document.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection.h" +#include "sp-root.h" +#include "xml/repr.h" + +#include "icon-preview.h" + +extern "C" { +// takes doc, root, icon, and icon name to produce pixels +guchar * +sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, + const gchar *name, unsigned int psize ); +} + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +IconPreviewPanel& +IconPreviewPanel::getInstance() +{ + static IconPreviewPanel &instance = *new IconPreviewPanel(); + + instance.refreshPreview(); + + return instance; +} + +//######################################################################### +//## E V E N T S +//######################################################################### + +void IconPreviewPanel::on_button_clicked(int which) +{ + if ( hot != which ) { + buttons[hot]->set_active( false ); + + hot = which; + updateMagnify(); + _getContents()->queue_draw(); + } +} + + + + +//######################################################################### +//## C O N S T R U C T O R / D E S T R U C T O R +//######################################################################### +/** + * Constructor + */ +IconPreviewPanel::IconPreviewPanel() : + UI::Widget::Panel("", "/dialogs/iconpreview", SP_VERB_VIEW_ICON_PREVIEW), + hot(1), + refreshButton(0), + selectionButton(0) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + numEntries = 0; + + std::vector<Glib::ustring> pref_sizes = prefs->getAllDirs("/iconpreview/sizes/default"); + std::vector<int> rawSizes; + + for (std::vector<Glib::ustring>::iterator i = pref_sizes.begin(); i != pref_sizes.end(); ++i) { + if (prefs->getBool(*i + "/show", true)) { + int sizeVal = prefs->getInt(*i + "/value", -1); + if (sizeVal > 0) { + rawSizes.push_back(sizeVal); + } + } + } + + if ( !rawSizes.empty() ) { + numEntries = rawSizes.size(); + sizes = new int[numEntries]; + int i = 0; + for ( std::vector<int>::iterator it = rawSizes.begin(); it != rawSizes.end(); ++it, ++i ) { + sizes[i] = *it; + } + } + + if ( numEntries < 1 ) + { + numEntries = 5; + sizes = new int[numEntries]; + sizes[0] = 16; + sizes[1] = 24; + sizes[2] = 32; + sizes[3] = 48; + sizes[4] = 128; + } + + pixMem = new guchar*[numEntries]; + images = new Gtk::Image*[numEntries]; + labels = new Glib::ustring*[numEntries]; + buttons = new Gtk::ToggleToolButton*[numEntries]; + + + for ( int i = 0; i < numEntries; i++ ) { + char *label = g_strdup_printf(_("%d x %d"), sizes[i], sizes[i]); + labels[i] = new Glib::ustring(label); + g_free(label); + pixMem[i] = 0; + images[i] = 0; + } + + + magLabel.set_label( *labels[hot] ); + + Gtk::VBox* magBox = new Gtk::VBox(); + + magBox->pack_start( magnified ); + magBox->pack_start( magLabel, Gtk::PACK_SHRINK ); + + + Gtk::VBox * verts = new Gtk::VBox(); + for ( int i = 0; i < numEntries; i++ ) { + pixMem[i] = new guchar[4 * sizes[i] * sizes[i]]; + memset( pixMem[i], 0x00, 4 * sizes[i] * sizes[i] ); + + GdkPixbuf *pb = gdk_pixbuf_new_from_data( pixMem[i], GDK_COLORSPACE_RGB, TRUE, 8, sizes[i], sizes[i], sizes[i] * 4, /*(GdkPixbufDestroyNotify)g_free*/NULL, NULL ); + GtkImage* img = GTK_IMAGE( gtk_image_new_from_pixbuf( pb ) ); + images[i] = Glib::wrap(img); + Glib::ustring label(*labels[i]); + buttons[i] = new Gtk::ToggleToolButton(label); + buttons[i]->set_active( i == hot ); + buttons[i]->set_icon_widget(*images[i]); + + tips.set_tip((*buttons[i]), label); + + buttons[i]->signal_clicked().connect( sigc::bind<int>( sigc::mem_fun(*this, &IconPreviewPanel::on_button_clicked), i) ); + + + verts->add(*buttons[i]); + } + + iconBox.pack_start(splitter); + splitter.pack1( *magBox, true, true ); + splitter.pack2( *verts, false, false ); + + + //## The Refresh button + + + Gtk::HButtonBox* holder = new Gtk::HButtonBox( Gtk::BUTTONBOX_END ); + _getContents()->pack_end(*holder, false, false); + + selectionButton = new Gtk::ToggleButton(_("Selection")); // , GTK_RESPONSE_APPLY + holder->pack_start( *selectionButton, false, false ); + tips.set_tip((*selectionButton), _("Selection only or whole document")); + selectionButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::modeToggled) ); + + gint val = prefs->getBool("/iconpreview/selectionOnly"); + selectionButton->set_active( val != 0 ); + + refreshButton = new Gtk::Button(Gtk::Stock::REFRESH); // , GTK_RESPONSE_APPLY + holder->pack_end( *refreshButton, false, false ); + tips.set_tip((*refreshButton), _("Refresh the icons")); + refreshButton->signal_clicked().connect( sigc::mem_fun(*this, &IconPreviewPanel::refreshPreview) ); + + + _getContents()->pack_start(iconBox, Gtk::PACK_EXPAND_WIDGET); + + show_all_children(); +} + +//######################################################################### +//## M E T H O D S +//######################################################################### + + +void IconPreviewPanel::refreshPreview() +{ + SPDesktop *desktop = getDesktop(); + if ( desktop ) { + + if ( selectionButton && selectionButton->get_active() ) + { + Inkscape::Selection * sel = sp_desktop_selection(desktop); + if ( sel ) { + //g_message("found a selection to play with"); + + GSList const *items = sel->itemList(); + SPObject *target = 0; + while ( items && !target ) { + SPItem* item = SP_ITEM( items->data ); + SPObject * obj = SP_OBJECT(item); + gchar const *id = SP_OBJECT_ID( obj ); + if ( id ) { + target = obj; + } + + items = g_slist_next(items); + } + if ( target ) { + renderPreview(target); + } + } + } + else + { + SPObject *target = desktop->currentRoot(); + if ( target ) { + renderPreview(target); + } + } + } +} + +void IconPreviewPanel::modeToggled() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/iconpreview/selectionOnly", (selectionButton && selectionButton->get_active())); + + refreshPreview(); +} + +void IconPreviewPanel::renderPreview( SPObject* obj ) +{ + SPDocument * doc = SP_OBJECT_DOCUMENT(obj); + gchar * id = SP_OBJECT_ID(obj); + +// g_message(" setting up to render '%s' as the icon", id ); + + NRArenaItem *root = NULL; + + /* Create new arena */ + NRArena *arena = NRArena::create(); + + /* Create ArenaItem and set transform */ + unsigned int visionkey = sp_item_display_key_new(1); + + root = sp_item_invoke_show ( SP_ITEM( SP_DOCUMENT_ROOT(doc) ), + arena, visionkey, SP_ITEM_SHOW_DISPLAY ); + + for ( int i = 0; i < numEntries; i++ ) { + guchar * px = sp_icon_doc_icon( doc, root, id, sizes[i] ); +// g_message( " size %d %s", sizes[i], (px ? "worked" : "failed") ); + if ( px ) { + memcpy( pixMem[i], px, sizes[i] * sizes[i] * 4 ); + g_free( px ); + px = 0; + } else { + memset( pixMem[i], 0, sizes[i] * sizes[i] * 4 ); + } + images[i]->queue_draw(); + } + updateMagnify(); + + sp_item_invoke_hide(SP_ITEM(sp_document_root(doc)), visionkey); + nr_object_unref((NRObject *) arena); +} + +void IconPreviewPanel::updateMagnify() +{ + Glib::RefPtr<Gdk::Pixbuf> buf = images[hot]->get_pixbuf()->scale_simple( 128, 128, Gdk::INTERP_NEAREST ); + magLabel.set_label( *labels[hot] ); + magnified.set( buf ); + magnified.queue_draw(); + magnified.get_parent()->queue_draw(); +} + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/icon-preview.h b/src/ui/dialog/icon-preview.h new file mode 100644 index 000000000..8f143725d --- /dev/null +++ b/src/ui/dialog/icon-preview.h @@ -0,0 +1,84 @@ +/** @file + * @brief A simple dialog for previewing icon representation. + */ +/* Authors: + * Jon A. Cruz + * Bob Jamison + * Other dudes from The Inkscape Organization + * + * Copyright (C) 2004,2005 The Inkscape Organization + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_ICON_PREVIEW_H +#define SEEN_ICON_PREVIEW_H + +#include <gtkmm/box.h> +#include <gtkmm/button.h> +#include <gtkmm/label.h> +#include <gtkmm/paned.h> +#include <gtkmm/image.h> +#include <gtkmm/togglebutton.h> +#include <gtkmm/toggletoolbutton.h> + +#include "ui/widget/panel.h" + +struct SPObject; + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays an icon preview + */ +class IconPreviewPanel : public UI::Widget::Panel +{ +public: + IconPreviewPanel(); + //IconPreviewPanel(Glib::ustring const &label); + + static IconPreviewPanel& getInstance(); + + void refreshPreview(); + void modeToggled(); + +private: + IconPreviewPanel(IconPreviewPanel const &); // no copy + IconPreviewPanel &operator=(IconPreviewPanel const &); // no assign + + + void on_button_clicked(int which); + void renderPreview( SPObject* obj ); + void updateMagnify(); + + Gtk::Tooltips tips; + + Gtk::VBox iconBox; + Gtk::HPaned splitter; + + int hot; + int numEntries; + int* sizes; + + Gtk::Image magnified; + Gtk::Label magLabel; + + Gtk::Button *refreshButton; + Gtk::ToggleButton *selectionButton; + + guchar** pixMem; + Gtk::Image** images; + Glib::ustring** labels; + Gtk::ToggleToolButton** buttons; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_ICON_PREVIEW_H diff --git a/src/ui/dialog/layer-properties.cpp b/src/ui/dialog/layer-properties.cpp new file mode 100644 index 000000000..ccd91fa2e --- /dev/null +++ b/src/ui/dialog/layer-properties.cpp @@ -0,0 +1,256 @@ +/** @file + * @brief Dialog for renaming layers + */ +/* Author: + * Bryce W. Harrington <bryce@bryceharrington.com> + * Andrius R. <knutux@gmail.com> + * + * Copyright (C) 2004 Bryce Harrington + * Copyright (C) 2006 Andrius R. + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#include <gtkmm/stock.h> +#include <glibmm/i18n.h> +#include "inkscape.h" +#include "desktop.h" +#include "document.h" +#include "layer-manager.h" +#include "message-stack.h" +#include "desktop-handles.h" +#include "sp-object.h" +#include "sp-item.h" + +#include "layer-properties.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +LayerPropertiesDialog::LayerPropertiesDialog() +: _strategy(NULL), _desktop(NULL), _layer(NULL), _position_visible(false) +{ + Gtk::VBox *mainVBox = get_vbox(); + + _layout_table.set_spacings(4); + _layout_table.resize (1, 2); + + // Layer name widgets + _layer_name_entry.set_activates_default(true); + _layer_name_label.set_label(_("Layer name:")); + _layer_name_label.set_alignment(1.0, 0.5); + + _layout_table.attach(_layer_name_label, + 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + _layout_table.attach(_layer_name_entry, + 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + mainVBox->pack_start(_layout_table, false, false, 4); + + // Buttons + _close_button.set_use_stock(true); + _close_button.set_label(Gtk::Stock::CANCEL.id); + _close_button.set_flags(Gtk::CAN_DEFAULT); + + _apply_button.set_use_underline(true); + _apply_button.set_flags(Gtk::CAN_DEFAULT); + + _close_button.signal_clicked() + .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)); + _apply_button.signal_clicked() + .connect(sigc::mem_fun(*this, &LayerPropertiesDialog::_apply)); + + signal_delete_event().connect( + sigc::bind_return( + sigc::hide(sigc::mem_fun(*this, &LayerPropertiesDialog::_close)), + true + ) + ); + + add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); + add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); + + _apply_button.grab_default(); + + show_all_children(); +} + +LayerPropertiesDialog::~LayerPropertiesDialog() { + _setDesktop(NULL); + _setLayer(NULL); +} + +void LayerPropertiesDialog::_showDialog(LayerPropertiesDialog::Strategy &strategy, + SPDesktop *desktop, SPObject *layer) +{ + LayerPropertiesDialog *dialog = new LayerPropertiesDialog(); + + dialog->_strategy = &strategy; + dialog->_setDesktop(desktop); + dialog->_setLayer(layer); + + dialog->_strategy->setup(*dialog); + + dialog->set_modal(true); + desktop->setWindowTransient (dialog->gobj()); + dialog->property_destroy_with_parent() = true; + + dialog->show(); + dialog->present(); +} + +void +LayerPropertiesDialog::_apply() +{ + g_assert(_strategy != NULL); + + _strategy->perform(*this); + sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_NONE, + _("Add layer")); + + _close(); +} + +void +LayerPropertiesDialog::_close() +{ + _setLayer(NULL); + _setDesktop(NULL); + destroy_(); + Glib::signal_idle().connect( + sigc::bind_return( + sigc::bind(sigc::ptr_fun(&::operator delete), this), + false + ) + ); +} + +void +LayerPropertiesDialog::_setup_position_controls() { + if ( NULL == _layer || _desktop->currentRoot() == _layer ) { + // no layers yet, so option above/below/sublayer is useless + return; + } + + _position_visible = true; + _dropdown_list = Gtk::ListStore::create(_dropdown_columns); + _layer_position_combo.set_model(_dropdown_list); + _layer_position_combo.pack_start(_label_renderer); + _layer_position_combo.set_cell_data_func(_label_renderer, + sigc::mem_fun(*this, &LayerPropertiesDialog::_prepareLabelRenderer)); + + _layout_table.resize (2, 2); + + Gtk::ListStore::iterator row; + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_ABOVE); + row->set_value(_dropdown_columns.name, Glib::ustring(_("Above current"))); + _layer_position_combo.set_active(row); + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_BELOW); + row->set_value(_dropdown_columns.name, Glib::ustring(_("Below current"))); + row = _dropdown_list->append(); + row->set_value(_dropdown_columns.position, LPOS_CHILD); + row->set_value(_dropdown_columns.name, Glib::ustring(_("As sublayer of current"))); + + _layout_table.attach(_layer_position_combo, + 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); + _layer_position_label.set_label(_("Position:")); + _layer_position_label.set_alignment(1.0, 0.5); + _layout_table.attach(_layer_position_label, + 0, 1, 1, 2, Gtk::FILL, Gtk::FILL); + show_all_children(); +} + +/** Formats the label for a given layer row + */ +void LayerPropertiesDialog::_prepareLabelRenderer( + Gtk::TreeModel::const_iterator const &row +) { + Glib::ustring name=(*row)[_dropdown_columns.name]; + _label_renderer.property_markup() = name.c_str(); +} + +void LayerPropertiesDialog::Rename::setup(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + dialog.set_title(_("Rename Layer")); + gchar const *name = desktop->currentLayer()->label(); + dialog._layer_name_entry.set_text(( name ? name : "" )); + dialog._apply_button.set_label(_("_Rename")); +} + +void LayerPropertiesDialog::Rename::perform(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + Glib::ustring name(dialog._layer_name_entry.get_text()); + desktop->layer_manager->renameLayer( desktop->currentLayer(), + ( name.empty() ? NULL : (gchar *)name.c_str() ) + ); + sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, + _("Rename layer")); + // TRANSLATORS: This means "The layer has been renamed" + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Renamed layer")); +} + +void LayerPropertiesDialog::Create::setup(LayerPropertiesDialog &dialog) { + dialog.set_title(_("Add Layer")); + dialog._layer_name_entry.set_text(""); + dialog._apply_button.set_label(_("_Add")); + dialog._setup_position_controls(); +} + +void LayerPropertiesDialog::Create::perform(LayerPropertiesDialog &dialog) { + SPDesktop *desktop=dialog._desktop; + + LayerRelativePosition position = LPOS_ABOVE; + + if (dialog._position_visible) { + Gtk::ListStore::iterator activeRow(dialog._layer_position_combo.get_active()); + position = activeRow->get_value(dialog._dropdown_columns.position); + } + + SPObject *new_layer=Inkscape::create_layer(desktop->currentRoot(), dialog._layer, position); + + Glib::ustring name(dialog._layer_name_entry.get_text()); + if (!name.empty()) { + desktop->layer_manager->renameLayer( new_layer, (gchar *)name.c_str() ); + } + sp_desktop_selection(desktop)->clear(); + desktop->setCurrentLayer(new_layer); + desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("New layer created.")); +} + +void LayerPropertiesDialog::_setDesktop(SPDesktop *desktop) { + if (desktop) { + Inkscape::GC::anchor (desktop); + } + if (_desktop) { + Inkscape::GC::release (_desktop); + } + _desktop = desktop; +} + +void LayerPropertiesDialog::_setLayer(SPObject *layer) { + if (layer) { + sp_object_ref(layer, NULL); + } + if (_layer) { + sp_object_unref(_layer, NULL); + } + _layer = layer; +} + +} // namespace +} // namespace +} // namespace + + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layer-properties.h b/src/ui/dialog/layer-properties.h new file mode 100644 index 000000000..807967e8d --- /dev/null +++ b/src/ui/dialog/layer-properties.h @@ -0,0 +1,132 @@ +/** @file + * @brief Dialog for renaming layers + */ +/* Author: + * Bryce W. Harrington <bryce@bryceharrington.com> + * + * Copyright (C) 2004 Bryce Harrington + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifndef INKSCAPE_DIALOG_LAYER_PROPERTIES_H +#define INKSCAPE_DIALOG_LAYER_PROPERTIES_H + +#include <gtkmm/dialog.h> +#include <gtkmm/notebook.h> +#include <gtkmm/separator.h> +#include <gtkmm/frame.h> +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/table.h> +#include <gtkmm/combobox.h> +#include <gtkmm/liststore.h> + +#include "selection.h" +#include "layer-fns.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +class LayerPropertiesDialog : public Gtk::Dialog { + public: + LayerPropertiesDialog(); + virtual ~LayerPropertiesDialog(); + + Glib::ustring getName() const { return "LayerPropertiesDialog"; } + + static void showRename(SPDesktop *desktop, SPObject *layer) { + _showDialog(Rename::instance(), desktop, layer); + } + static void showCreate(SPDesktop *desktop, SPObject *layer) { + _showDialog(Create::instance(), desktop, layer); + } + +protected: + struct Strategy { + virtual ~Strategy() {} + virtual void setup(LayerPropertiesDialog &)=0; + virtual void perform(LayerPropertiesDialog &)=0; + }; + struct Rename : public Strategy { + static Rename &instance() { static Rename instance; return instance; } + void setup(LayerPropertiesDialog &dialog); + void perform(LayerPropertiesDialog &dialog); + }; + struct Create : public Strategy { + static Create &instance() { static Create instance; return instance; } + void setup(LayerPropertiesDialog &dialog); + void perform(LayerPropertiesDialog &dialog); + }; + + friend class Rename; + friend class Create; + + Strategy *_strategy; + SPDesktop *_desktop; + SPObject *_layer; + + class PositionDropdownColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<LayerRelativePosition> position; + Gtk::TreeModelColumn<Glib::ustring> name; + + PositionDropdownColumns() { + add(position); add(name); + } + }; + + Gtk::Label _layer_name_label; + Gtk::Entry _layer_name_entry; + Gtk::Label _layer_position_label; + Gtk::ComboBox _layer_position_combo; + Gtk::Table _layout_table; + bool _position_visible; + + PositionDropdownColumns _dropdown_columns; + Gtk::CellRendererText _label_renderer; + Glib::RefPtr<Gtk::ListStore> _dropdown_list; + + Gtk::Button _close_button; + Gtk::Button _apply_button; + + sigc::connection _destroy_connection; + + static LayerPropertiesDialog &_instance() { + static LayerPropertiesDialog instance; + return instance; + } + + void _setDesktop(SPDesktop *desktop); + void _setLayer(SPObject *layer); + + static void _showDialog(Strategy &strategy, SPDesktop *desktop, SPObject *layer); + void _apply(); + void _close(); + + void _setup_position_controls(); + void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); + +private: + LayerPropertiesDialog(LayerPropertiesDialog const &); // no copy + LayerPropertiesDialog &operator=(LayerPropertiesDialog const &); // no assign +}; + +} // namespace +} // namespace +} // namespace + + +#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp new file mode 100644 index 000000000..0e75401ab --- /dev/null +++ b/src/ui/dialog/layers.cpp @@ -0,0 +1,805 @@ +/* + * A simple panel for layers + * + * Authors: + * Jon A. Cruz + * + * Copyright (C) 2006 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtkstock.h> +#include <gtk/gtkmain.h> +#include <gtkmm/widget.h> +#include <gtkmm/icontheme.h> +#include <glibmm/i18n.h> + +#include "desktop.h" +#include "desktop-style.h" +#include "document.h" +#include "helper/action.h" +#include "inkscape.h" +#include "layer-fns.h" +#include "layer-manager.h" +#include "preferences.h" +#include "sp-item.h" +#include "sp-object.h" +#include "svg/css-ostringstream.h" +#include "ui/icon-names.h" +#include "ui/widget/imagetoggler.h" +#include "verbs.h" +#include "widgets/icon.h" +#include "xml/repr.h" + +#include "layers.h" + +//#define DUMP_LAYERS 1 + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +LayersPanel& +LayersPanel::getInstance() +{ + return *new LayersPanel(); +} + +enum { + COL_VISIBLE = 1, + COL_LOCKED +}; + +enum { + BUTTON_NEW = 0, + BUTTON_RENAME, + BUTTON_TOP, + BUTTON_BOTTOM, + BUTTON_UP, + BUTTON_DOWN, + BUTTON_DUPLICATE, + BUTTON_DELETE, + BUTTON_SOLO +}; + +class LayersPanel::InternalUIBounce +{ +public: + int _actionCode; + SPObject* _target; +}; + +static gboolean layers_panel_activated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) +{ + if ( data ) + { + LayersPanel* panel = reinterpret_cast<LayersPanel*>(data); + panel->setDesktop(panel->getDesktop()); + } + + return FALSE; +} + +static gboolean layers_panel_deactivated( GtkObject */*object*/, GdkEvent * /*event*/, gpointer data ) +{ + if ( data ) + { + LayersPanel* panel = reinterpret_cast<LayersPanel*>(data); + panel->setDesktop(NULL); + } + + return FALSE; +} + + +void LayersPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ) +{ + bool set = false; + + if ( iconName ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + set = true; + } + + if ( desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(desktop); + if ( !set && action && action->image ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + set = true; + } + + if ( action && action->tip ) { + _tips.set_tip( btn, action->tip ); + } + } + } + + if ( !set && fallback ) { + btn.set_label( fallback ); + } +} + + +Gtk::MenuItem& LayersPanel::_addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ) +{ + GtkWidget* iconWidget = 0; + const char* label = 0; + + if ( iconName ) { + iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, iconName ); + } + + if ( desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(desktop); + if ( !iconWidget && action && action->image ) { + iconWidget = sp_icon_new( Inkscape::ICON_SIZE_MENU, action->image ); + } + + if ( action ) { + label = action->name; + } + } + } + + if ( !label && fallback ) { + label = fallback; + } + + Gtk::Widget* wrapped = 0; + if ( iconWidget ) { + wrapped = manage(Glib::wrap(iconWidget)); + wrapped->show(); + } + + + + Gtk::Menu::MenuList& menulist = _popupMenu.items(); + + if ( wrapped ) { + menulist.push_back( Gtk::Menu_Helpers::ImageMenuElem( label, *wrapped, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); + } else { + menulist.push_back( Gtk::Menu_Helpers::MenuElem( label, sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), id)) ); + } + return menulist.back(); +} + +void LayersPanel::_fireAction( unsigned int code ) +{ + if ( _desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(_desktop); + if ( action ) { + sp_action_perform( action, NULL ); +// } else { +// g_message("no action"); + } +// } else { +// g_message("no verb for %u", code); + } +// } else { +// g_message("no active desktop"); + } +} + +// SP_VERB_LAYER_NEXT, +// SP_VERB_LAYER_PREV, +void LayersPanel::_takeAction( int val ) +{ + if ( !_pending ) { + _pending = new InternalUIBounce(); + _pending->_actionCode = val; + _pending->_target = _selectedLayer(); + Glib::signal_timeout().connect( sigc::mem_fun(*this, &LayersPanel::_executeAction), 0 ); + } +} + +bool LayersPanel::_executeAction() +{ + // Make sure selected layer hasn't changed since the action was triggered + if ( _pending + && ( + (_pending->_actionCode == BUTTON_NEW) + || !( (_desktop && _desktop->currentLayer()) + && (_desktop->currentLayer() != _pending->_target) + ) + ) + ) { + int val = _pending->_actionCode; +// SPObject* target = _pending->_target; + + switch ( val ) { + case BUTTON_NEW: + { + _fireAction( SP_VERB_LAYER_NEW ); + } + break; + case BUTTON_RENAME: + { + _fireAction( SP_VERB_LAYER_RENAME ); + } + break; + case BUTTON_TOP: + { + _fireAction( SP_VERB_LAYER_TO_TOP ); + } + break; + case BUTTON_BOTTOM: + { + _fireAction( SP_VERB_LAYER_TO_BOTTOM ); + } + break; + case BUTTON_UP: + { + _fireAction( SP_VERB_LAYER_RAISE ); + } + break; + case BUTTON_DOWN: + { + _fireAction( SP_VERB_LAYER_LOWER ); + } + break; + case BUTTON_DUPLICATE: + { + _fireAction( SP_VERB_LAYER_DUPLICATE ); + } + break; + case BUTTON_DELETE: + { + _fireAction( SP_VERB_LAYER_DELETE ); + } + case BUTTON_SOLO: + { + _fireAction( SP_VERB_LAYER_SOLO ); + } + break; + } + + delete _pending; + _pending = 0; + } + + return false; +} + +class LayersPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + + ModelColumns() + { + add(_colObject); + add(_colVisible); + add(_colLocked); + add(_colLabel); + } + virtual ~ModelColumns() {} + + Gtk::TreeModelColumn<SPObject*> _colObject; + Gtk::TreeModelColumn<Glib::ustring> _colLabel; + Gtk::TreeModelColumn<bool> _colVisible; + Gtk::TreeModelColumn<bool> _colLocked; +}; + +void LayersPanel::_updateLayer( SPObject *layer ) { + _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForUpdated), layer) ); +} + +bool LayersPanel::_checkForUpdated(const Gtk::TreePath &/*path*/, const Gtk::TreeIter& iter, SPObject* layer) +{ + bool stopGoing = false; + Gtk::TreeModel::Row row = *iter; + Glib::ustring tmp = row[_model->_colLabel]; + if ( layer == row[_model->_colObject] ) + { + row[_model->_colLabel] = layer->label() ? layer->label() : SP_OBJECT_ID(layer); + row[_model->_colVisible] = SP_IS_ITEM(layer) ? !SP_ITEM(layer)->isHidden() : false; + row[_model->_colLocked] = SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false; + + stopGoing = true; + } + + return stopGoing; +} + +void LayersPanel::_selectLayer( SPObject *layer ) { + if ( !layer || (_desktop && _desktop->doc() && (layer == _desktop->doc()->root)) ) { + if ( _tree.get_selection()->count_selected_rows() != 0 ) { + _tree.get_selection()->unselect_all(); + } + } else { + _store->foreach( sigc::bind<SPObject*>(sigc::mem_fun(*this, &LayersPanel::_checkForSelected), layer) ); + } + + _checkTreeSelection(); +} + +bool LayersPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer) +{ + bool stopGoing = false; + + Gtk::TreeModel::Row row = *iter; + if ( layer == row[_model->_colObject] ) + { + _tree.expand_to_path( path ); + + Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection(); + + select->select(iter); + + stopGoing = true; + } + + return stopGoing; +} + +void LayersPanel::_layersChanged() +{ +// g_message("_layersChanged()"); + SPDocument* document = _desktop->doc(); + SPObject* root = document->root; + if ( root ) { + _selectedConnection.block(); + if ( _mgr && _mgr->includes( root ) ) { + SPObject* target = _desktop->currentLayer(); + _store->clear(); + +#if DUMP_LAYERS + g_message("root:%p {%s} [%s]", root, root->id, root->label() ); +#endif // DUMP_LAYERS + _addLayer( document, root, 0, target, 0 ); + } + _selectedConnection.unblock(); + } +} + +void LayersPanel::_addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ) +{ + if ( layer && (level < _maxNestDepth) ) { + unsigned int counter = _mgr->childCount(layer); + for ( unsigned int i = 0; i < counter; i++ ) { + SPObject *child = _mgr->nthChildOf(layer, i); + if ( child ) { +#if DUMP_LAYERS + g_message(" %3d layer:%p {%s} [%s]", level, child, child->id, child->label() ); +#endif // DUMP_LAYERS + + Gtk::TreeModel::iterator iter = parentRow ? _store->prepend(parentRow->children()) : _store->prepend(); + Gtk::TreeModel::Row row = *iter; + row[_model->_colObject] = child; + row[_model->_colLabel] = child->label() ? child->label() : SP_OBJECT_ID(child); + row[_model->_colVisible] = SP_IS_ITEM(child) ? !SP_ITEM(child)->isHidden() : false; + row[_model->_colLocked] = SP_IS_ITEM(child) ? SP_ITEM(child)->isLocked() : false; + + if ( target && child == target ) { + _tree.expand_to_path( _store->get_path(iter) ); + + Glib::RefPtr<Gtk::TreeSelection> select = _tree.get_selection(); + select->select(iter); + + _checkTreeSelection(); + } + + _addLayer( doc, child, &row, target, level + 1 ); + } + } + } +} + +SPObject* LayersPanel::_selectedLayer() +{ + SPObject* obj = 0; + + Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + if ( iter ) { + Gtk::TreeModel::Row row = *iter; + obj = row[_model->_colObject]; + } + + return obj; +} + +void LayersPanel::_pushTreeSelectionToCurrent() +{ + SPObject* inTree = _selectedLayer(); + // TODO hunt down the possible API abuse in getting NULL + if ( _desktop->currentRoot() ) { + if ( inTree ) { + SPObject* curr = _desktop->currentLayer(); + if ( curr != inTree ) { + _mgr->setCurrentLayer( inTree ); + } + } else { + _mgr->setCurrentLayer( _desktop->doc()->root ); + } + } +} + +void LayersPanel::_checkTreeSelection() +{ + bool sensitive = false; + bool sensitiveNonTop = false; + bool sensitiveNonBottom = false; + if ( _tree.get_selection()->count_selected_rows() > 0 ) { + sensitive = true; + + SPObject* inTree = _selectedLayer(); + if ( inTree ) { + + sensitiveNonTop = (Inkscape::next_layer(inTree->parent, inTree) != 0); + sensitiveNonBottom = (Inkscape::previous_layer(inTree->parent, inTree) != 0); + + } + } + + + for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) { + (*it)->set_sensitive( sensitive ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { + (*it)->set_sensitive( sensitiveNonTop ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { + (*it)->set_sensitive( sensitiveNonBottom ); + } +} + +void LayersPanel::_preToggle( GdkEvent const *event ) +{ + if ( _toggleEvent ) { + gdk_event_free(_toggleEvent); + _toggleEvent = 0; + } + + if ( event && (event->type == GDK_BUTTON_PRESS) ) { + // Make a copy so we can keep it around. + _toggleEvent = gdk_event_copy(const_cast<GdkEvent*>(event)); + } +} + +void LayersPanel::_toggled( Glib::ustring const& str, int targetCol ) +{ + Gtk::TreeModel::Children::iterator iter = _tree.get_model()->get_iter(str); + Gtk::TreeModel::Row row = *iter; + + Glib::ustring tmp = row[_model->_colLabel]; + + SPObject* obj = row[_model->_colObject]; + SPItem* item = ( obj && SP_IS_ITEM(obj) ) ? SP_ITEM(obj) : 0; + if ( item ) { + switch ( targetCol ) { + case COL_VISIBLE: + { + bool newValue = !row[_model->_colVisible]; + row[_model->_colVisible] = newValue; + item->setHidden( !newValue ); + item->updateRepr(); + sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, + newValue? _("Unhide layer") : _("Hide layer")); + } + break; + + case COL_LOCKED: + { + bool newValue = !row[_model->_colLocked]; + row[_model->_colLocked] = newValue; + item->setLocked( newValue ); + item->updateRepr(); + sp_document_done( _desktop->doc() , SP_VERB_DIALOG_LAYERS, + newValue? _("Lock layer") : _("Unlock layer")); + } + break; + } + } +} + +void LayersPanel::_handleButtonEvent(GdkEventButton* evt) +{ + // TODO - fix to a better is-popup function + if ( (evt->type == GDK_BUTTON_PRESS) && (evt->button == 3) ) { + + + { + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn* col = 0; + int x = static_cast<int>(evt->x); + int y = static_cast<int>(evt->y); + int x2 = 0; + int y2 = 0; + if ( _tree.get_path_at_pos( x, y, + path, col, + x2, y2 ) ) { + _checkTreeSelection(); + _popupMenu.popup(evt->button, evt->time); + } + } + + } +} + +void LayersPanel::_handleRowChange( Gtk::TreeModel::Path const& /*path*/, Gtk::TreeModel::iterator const& iter ) +{ + Gtk::TreeModel::Row row = *iter; + if ( row ) { + SPObject* obj = row[_model->_colObject]; + if ( obj ) { + gchar const* oldLabel = obj->label(); + Glib::ustring tmp = row[_model->_colLabel]; + if ( oldLabel && oldLabel[0] && !tmp.empty() && (tmp != oldLabel) ) { + _mgr->renameLayer( obj, tmp.c_str() ); + row[_model->_colLabel] = obj->label(); + } + } + } +} + +bool LayersPanel::_rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & /*model*/, Gtk::TreeModel::Path const & /*path*/, bool currentlySelected ) +{ + bool val = true; + if ( !currentlySelected && _toggleEvent ) + { + GdkEvent* event = gtk_get_current_event(); + if ( event ) { + // (keep these checks separate, so we know when to call gdk_event_free() + if ( event->type == GDK_BUTTON_PRESS ) { + GdkEventButton const* target = reinterpret_cast<GdkEventButton const*>(_toggleEvent); + GdkEventButton const* evtb = reinterpret_cast<GdkEventButton const*>(event); + + if ( (evtb->window == target->window) + && (evtb->send_event == target->send_event) + && (evtb->time == target->time) + && (evtb->state == target->state) + ) + { + // Ooooh! It's a magic one + val = false; + } + } + gdk_event_free(event); + } + } + return val; +} + +/** + * Constructor + */ +LayersPanel::LayersPanel() : + UI::Widget::Panel("", "/dialogs/layers", SP_VERB_DIALOG_LAYERS), + _maxNestDepth(20), + _mgr(0), + _desktop(0), + _model(0), + _pending(0), + _toggleEvent(0), + _compositeSettings(SP_VERB_DIALOG_LAYERS, "layers", UI::Widget::SimpleFilterModifier::BLEND) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + _maxNestDepth = prefs->getIntLimited("/dialogs/layers/maxDepth", 20, 1, 1000); + + ModelColumns *zoop = new ModelColumns(); + _model = zoop; + + _store = Gtk::TreeStore::create( *zoop ); + + _tree.set_model( _store ); + _tree.set_headers_visible(false); + + Inkscape::UI::Widget::ImageToggler *eyeRenderer = manage( new Inkscape::UI::Widget::ImageToggler( + INKSCAPE_ICON_OBJECT_VISIBLE, INKSCAPE_ICON_OBJECT_HIDDEN) ); + int visibleColNum = _tree.append_column("vis", *eyeRenderer) - 1; + eyeRenderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); + eyeRenderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_VISIBLE) ); + eyeRenderer->property_activatable() = true; + Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum); + if ( col ) { + col->add_attribute( eyeRenderer->property_active(), _model->_colVisible ); + } + + Inkscape::UI::Widget::ImageToggler * renderer = manage( new Inkscape::UI::Widget::ImageToggler( + INKSCAPE_ICON_OBJECT_LOCKED, INKSCAPE_ICON_OBJECT_UNLOCKED) ); + int lockedColNum = _tree.append_column("lock", *renderer) - 1; + renderer->signal_pre_toggle().connect( sigc::mem_fun(*this, &LayersPanel::_preToggle) ); + renderer->signal_toggled().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_toggled), (int)COL_LOCKED) ); + renderer->property_activatable() = true; + col = _tree.get_column(lockedColNum); + if ( col ) { + col->add_attribute( renderer->property_active(), _model->_colLocked ); + } + + int nameColNum = _tree.append_column_editable("Name", _model->_colLabel) - 1; + + _tree.set_expander_column( *_tree.get_column(nameColNum) ); + + _compositeSettings.setSubject(&_subject); + + _selectedConnection = _tree.get_selection()->signal_changed().connect( sigc::mem_fun(*this, &LayersPanel::_pushTreeSelectionToCurrent) ); + _tree.get_selection()->set_select_function( sigc::mem_fun(*this, &LayersPanel::_rowSelectFunction) ); + + _tree.get_model()->signal_row_changed().connect( sigc::mem_fun(*this, &LayersPanel::_handleRowChange) ); + _tree.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LayersPanel::_handleButtonEvent) ); + + _scroller.add( _tree ); + _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scroller.set_shadow_type(Gtk::SHADOW_IN); + + _watching.push_back( &_compositeSettings ); + + _layersPage.pack_start( _scroller, Gtk::PACK_EXPAND_WIDGET ); + _layersPage.pack_end(_compositeSettings, Gtk::PACK_SHRINK); + _layersPage.pack_end(_buttonsRow, Gtk::PACK_SHRINK); + + _notebook.append_page(_layersPage, _("Layers")); + + _getContents()->pack_start(_notebook, Gtk::PACK_EXPAND_WIDGET); + + SPDesktop* targetDesktop = getDesktop(); + + _buttonsRow.set_child_min_width( 16 ); + + Gtk::Button* btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("New") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_NEW) ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_TOP, GTK_STOCK_GOTO_TOP, _("Top") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_TOP) ); + _watchingNonTop.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, _("Up") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_UP) ); + _watchingNonTop.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, _("Dn") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DOWN) ); + _watchingNonBottom.push_back( btn ); + _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_TO_BOTTOM, GTK_STOCK_GOTO_BOTTOM, _("Bot") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_BOTTOM) ); + _watchingNonBottom.push_back( btn ); + _buttonsRow.add( *btn ); + +// btn = manage( new Gtk::Button("Dup") ); +// btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DUPLICATE) ); +// _buttonsRow.add( *btn ); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, targetDesktop, SP_VERB_LAYER_DELETE, GTK_STOCK_REMOVE, _("X") ); + btn->signal_clicked().connect( sigc::bind( sigc::mem_fun(*this, &LayersPanel::_takeAction), (int)BUTTON_DELETE) ); + _watching.push_back( btn ); + _buttonsRow.add( *btn ); + + + + + // ------------------------------------------------------- + { + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) ); + + _popupMenu.items().push_back( Gtk::Menu_Helpers::SeparatorElem() ); + + _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) ); + _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) ); + + _popupMenu.show_all_children(); + } + // ------------------------------------------------------- + + + + for ( std::vector<Gtk::Widget*>::iterator it = _watching.begin(); it != _watching.end(); ++it ) { + (*it)->set_sensitive( false ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonTop.begin(); it != _watchingNonTop.end(); ++it ) { + (*it)->set_sensitive( false ); + } + for ( std::vector<Gtk::Widget*>::iterator it = _watchingNonBottom.begin(); it != _watchingNonBottom.end(); ++it ) { + (*it)->set_sensitive( false ); + } + + g_signal_connect( G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK( layers_panel_activated ), this ); + g_signal_connect( G_OBJECT(INKSCAPE), "deactivate_desktop", G_CALLBACK( layers_panel_deactivated ), this ); + setDesktop( targetDesktop ); + + show_all_children(); + + // restorePanelPrefs(); +} + +LayersPanel::~LayersPanel() +{ + setDesktop(NULL); + + _compositeSettings.setSubject(NULL); + + if ( _model ) + { + delete _model; + } + + if ( _toggleEvent ) + { + gdk_event_free( _toggleEvent ); + _toggleEvent = 0; + } +} + + +void LayersPanel::setDesktop( SPDesktop* desktop ) +{ + Panel::setDesktop(desktop); + + if ( desktop != _desktop ) { + _layerChangedConnection.disconnect(); + _layerUpdatedConnection.disconnect(); + _changedConnection.disconnect(); + if ( _mgr ) { + _mgr = 0; + } + if ( _desktop ) { + _desktop = 0; + } + + _desktop = getDesktop(); + if ( _desktop ) { + //setLabel( _desktop->doc()->name ); + + _mgr = _desktop->layer_manager; + if ( _mgr ) { + _layerChangedConnection = _mgr->connectCurrentLayerChanged( sigc::mem_fun(*this, &LayersPanel::_selectLayer) ); + _layerUpdatedConnection = _mgr->connectLayerDetailsChanged( sigc::mem_fun(*this, &LayersPanel::_updateLayer) ); + _changedConnection = _mgr->connectChanged( sigc::mem_fun(*this, &LayersPanel::_layersChanged) ); + } + + _layersChanged(); + } + } +/* + GSList const *layers=sp_document_get_resource_list( _desktop->doc(), "layer" ); + g_message( "layers list starts at %p", layers ); + for ( GSList const *iter=layers ; iter ; iter = iter->next ) { + SPObject *layer=static_cast<SPObject *>(iter->data); + g_message(" {%s} [%s]", layer->id, layer->label() ); + } +*/ +} + + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/layers.h b/src/ui/dialog/layers.h new file mode 100644 index 000000000..1f593b9c6 --- /dev/null +++ b/src/ui/dialog/layers.h @@ -0,0 +1,146 @@ +/* + * A simple dialog for layer UI. + * + * Authors: + * Jon A. Cruz + * + * Copyright (C) 2006 Jon A. Cruz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_LAYERS_PANEL_H +#define SEEN_LAYERS_PANEL_H + +#include <gtkmm/treeview.h> +#include <gtkmm/treestore.h> +#include <gtkmm/tooltips.h> +#include <gtkmm/scale.h> +#include <gtkmm/scrolledwindow.h> +#include <gtkmm/box.h> +#include <gtkmm/buttonbox.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/notebook.h> + +//#include "ui/previewholder.h" +#include "ui/widget/panel.h" +#include "ui/widget/object-composite-settings.h" + +class SPObject; + +namespace Inkscape { + +class LayerManager; + +namespace UI { +namespace Dialogs { + + +/** + * A panel that displays layers. + */ +class LayersPanel : public UI::Widget::Panel +{ +public: + LayersPanel(); + virtual ~LayersPanel(); + + //virtual void setOrientation( Gtk::AnchorType how ); + + static LayersPanel& getInstance(); + + void setDesktop( SPDesktop* desktop ); + +protected: + //virtual void _handleAction( int setId, int itemId ); + +private: + class ModelColumns; + class InternalUIBounce; + + LayersPanel(LayersPanel const &); // no copy + LayersPanel &operator=(LayersPanel const &); // no assign + + void _styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ); + void _fireAction( unsigned int code ); + Gtk::MenuItem& _addPopupItem( SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback, int id ); + + void _preToggle( GdkEvent const *event ); + void _toggled( Glib::ustring const& str, int targetCol ); + + void _handleButtonEvent(GdkEventButton* evt); + void _handleRowChange( Gtk::TreeModel::Path const& path, Gtk::TreeModel::iterator const& iter ); + + void _pushTreeSelectionToCurrent(); + void _checkTreeSelection(); + + void _takeAction( int val ); + bool _executeAction(); + + bool _rowSelectFunction( Glib::RefPtr<Gtk::TreeModel> const & model, Gtk::TreeModel::Path const & path, bool b ); + + void _updateLayer(SPObject *layer); + bool _checkForUpdated(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPObject* layer); + + void _selectLayer(SPObject *layer); + bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPObject* layer); + + void _layersChanged(); + void _addLayer( SPDocument* doc, SPObject* layer, Gtk::TreeModel::Row* parentRow, SPObject* target, int level ); + + SPObject* _selectedLayer(); + + // Hooked to the layer manager: + sigc::connection _layerChangedConnection; + sigc::connection _layerUpdatedConnection; + sigc::connection _changedConnection; + sigc::connection _addedConnection; + sigc::connection _removedConnection; + + // Internal + sigc::connection _selectedConnection; + + int _maxNestDepth; + Inkscape::LayerManager* _mgr; + SPDesktop* _desktop; + ModelColumns* _model; + InternalUIBounce* _pending; + GdkEvent* _toggleEvent; + Glib::RefPtr<Gtk::TreeStore> _store; + std::vector<Gtk::Widget*> _watching; + std::vector<Gtk::Widget*> _watchingNonTop; + std::vector<Gtk::Widget*> _watchingNonBottom; + + Gtk::Tooltips _tips; + Gtk::TreeView _tree; + Gtk::HButtonBox _buttonsRow; + Gtk::ScrolledWindow _scroller; + Gtk::Menu _popupMenu; + Gtk::SpinButton _spinBtn; + Gtk::Notebook _notebook; + Gtk::VBox _layersPage; + + UI::Widget::StyleSubject::CurrentLayer _subject; + UI::Widget::ObjectCompositeSettings _compositeSettings; +}; + + + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_LAYERS_PANEL_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/panel-dialog.h b/src/ui/dialog/panel-dialog.h index f087f40e4..7dbb6dd4a 100644 --- a/src/ui/dialog/panel-dialog.h +++ b/src/ui/dialog/panel-dialog.h @@ -19,7 +19,7 @@ #include "verbs.h" #include "dialog.h" -#include "dialogs/swatches.h" +#include "ui/dialog/swatches.h" #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" #include "preferences.h" diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp new file mode 100644 index 000000000..dfb60c04e --- /dev/null +++ b/src/ui/dialog/swatches.cpp @@ -0,0 +1,1212 @@ +/** @file + * @brief Color swatches dialog + */ +/* Authors: + * Jon A. Cruz + * John Bintz + * + * Copyright (C) 2005 Jon A. Cruz + * Copyright (C) 2008 John Bintz + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <errno.h> + +#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types +#include <gtk/gtkdnd.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkseparatormenuitem.h> +#include <glibmm/i18n.h> +#include <gdkmm/pixbuf.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "document.h" +#include "extension/db.h" +#include "inkscape.h" +#include "inkscape.h" +#include "io/sys.h" +#include "message-context.h" +#include "path-prefix.h" +#include "preferences.h" +#include "sp-item.h" +#include "svg/svg-color.h" +#include "swatches.h" +#include "widgets/eek-preview.h" + +namespace Inkscape { +namespace UI { +namespace Dialogs { + +ColorItem::ColorItem() : _isRemove(true){}; +ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) : + def( r, g, b, name ), + _isRemove(false), + _isLive(false), + _linkIsTone(false), + _linkPercent(0), + _linkGray(0), + _linkSrc(0) +{ +} + +ColorItem::~ColorItem() +{ +} + +ColorItem::ColorItem(ColorItem const &other) : + Inkscape::UI::Previewable() +{ + if ( this != &other ) { + *this = other; + } +} + +ColorItem &ColorItem::operator=(ColorItem const &other) +{ + if ( this != &other ) { + def = other.def; + + // TODO - correct linkage + _linkSrc = other._linkSrc; + g_message("Erk!"); + } + return *this; +} + + +class JustForNow +{ +public: + JustForNow() : _prefWidth(0) {} + + Glib::ustring _name; + int _prefWidth; + std::vector<ColorItem*> _colors; +}; + +static std::vector<JustForNow*> possible; + + + +typedef enum { + APP_X_INKY_COLOR_ID = 0, + APP_X_INKY_COLOR = 0, + APP_X_COLOR, + TEXT_DATA +} colorFlavorType; + +//TODO: warning: deprecated conversion from string constant to ‘gchar*’ +// +//Turn out to be warnings that we should probably leave in place. The +// pointers/types used need to be read-only. So until we correct the using +// code, those warnings are actually desired. They say "Hey! Fix this". We +// definitely don't want to hide/ignore them. --JonCruz +static const GtkTargetEntry sourceColorEntries[] = { +#if ENABLE_MAGIC_COLORS +// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, + {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, +#endif // ENABLE_MAGIC_COLORS + {"application/x-color", 0, APP_X_COLOR}, + {"text/plain", 0, TEXT_DATA}, +}; + +void ColorItem::_dragGetColorData( GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data) +{ + (void)widget; + (void)drag_context; + (void)time; + static GdkAtom typeXColor = gdk_atom_intern("application/x-color", FALSE); + static GdkAtom typeText = gdk_atom_intern("text/plain", FALSE); + + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( info == TEXT_DATA ) { + gchar* tmp = g_strdup_printf("#%02x%02x%02x", item->def.getR(), item->def.getG(), item->def.getB() ); + + gtk_selection_data_set( data, + typeText, + 8, // format + (guchar*)tmp, + strlen((const char*)tmp) + 1); + g_free(tmp); + tmp = 0; + } else if ( info == APP_X_INKY_COLOR ) { + Glib::ustring paletteName; + + // Find where this thing came from + bool found = false; + int index = 0; + for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end() && !found; ++it ) { + JustForNow* curr = *it; + index = 0; + for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { + if ( item == *zz ) { + found = true; + paletteName = curr->_name; + break; + } else { + index++; + } + } + } + +// if ( found ) { +// g_message("Found the color at entry %d in palette '%s'", index, paletteName.c_str() ); +// } else { +// g_message("Unable to find the color"); +// } + int itemCount = 4 + 2 + 1 + paletteName.length(); + + guint16* tmp = new guint16[itemCount]; + tmp[0] = (item->def.getR() << 8) | item->def.getR(); + tmp[1] = (item->def.getG() << 8) | item->def.getG(); + tmp[2] = (item->def.getB() << 8) | item->def.getB(); + tmp[3] = 0xffff; + tmp[4] = (item->_isLive || !item->_listeners.empty() || (item->_linkSrc != 0) ) ? 1 : 0; + + tmp[5] = index; + tmp[6] = paletteName.length(); + for ( unsigned int i = 0; i < paletteName.length(); i++ ) { + tmp[7 + i] = paletteName[i]; + } + gtk_selection_data_set( data, + typeXColor, + 16, // format + reinterpret_cast<const guchar*>(tmp), + itemCount * 2); + delete[] tmp; + } else { + guint16 tmp[4]; + tmp[0] = (item->def.getR() << 8) | item->def.getR(); + tmp[1] = (item->def.getG() << 8) | item->def.getG(); + tmp[2] = (item->def.getB() << 8) | item->def.getB(); + tmp[3] = 0xffff; + gtk_selection_data_set( data, + typeXColor, + 16, // format + reinterpret_cast<const guchar*>(tmp), + (3+1) * 2); + } +} + +static void dragBegin( GtkWidget *widget, GdkDragContext* dc, gpointer data ) +{ + (void)widget; + ColorItem* item = reinterpret_cast<ColorItem*>(data); + if ( item ) + { + if (item->isRemove()){ + GError *error = NULL; + gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); + gsize bytesRead = 0; + gsize bytesWritten = 0; + gchar *localFilename = g_filename_from_utf8( filepath, + -1, + &bytesRead, + &bytesWritten, + &error); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(localFilename, 32, 24, FALSE, &error); + g_free(localFilename); + g_free(filepath); + gtk_drag_set_icon_pixbuf( dc, pixbuf, 0, 0 ); + return; + } + + Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, 32, 24 ); + guint32 fillWith = (0xff000000 & (item->def.getR() << 24)) + | (0x00ff0000 & (item->def.getG() << 16)) + | (0x0000ff00 & (item->def.getB() << 8)); + thumb->fill( fillWith ); + gtk_drag_set_icon_pixbuf( dc, thumb->gobj(), 0, 0 ); + } + +} + +//"drag-drop" +// gboolean dragDropColorData( GtkWidget *widget, +// GdkDragContext *drag_context, +// gint x, +// gint y, +// guint time, +// gpointer user_data) +// { +// // TODO finish + +// return TRUE; +// } + +static void handleClick( GtkWidget* widget, gpointer callback_data ) { + (void)widget; + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + item->buttonClicked(false); + } +} + +static void handleSecondaryClick( GtkWidget* widget, gint arg1, gpointer callback_data ) { + (void)widget; + (void)arg1; + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + item->buttonClicked(true); + } +} + +static gboolean handleEnterNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + gchar* msg = g_strdup_printf(_("Color: <b>%s</b>; <b>Click</b> to set fill, <b>Shift+click</b> to set stroke"), + item->def.descr.c_str()); + desktop->tipsMessageContext()->set(Inkscape::INFORMATION_MESSAGE, msg); + g_free(msg); + } + } + return FALSE; +} + +static gboolean handleLeaveNotify( GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, gpointer callback_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); + if ( item ) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + desktop->tipsMessageContext()->clear(); + } + } + return FALSE; +} + +static GtkWidget* popupMenu = 0; +static ColorItem* bounceTarget = 0; + +static void redirClick( GtkMenuItem *menuitem, gpointer user_data ) +{ + (void)user_data; + if ( bounceTarget ) { + handleClick( GTK_WIDGET(menuitem), bounceTarget ); + } +} + +static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer user_data ) +{ + (void)user_data; + if ( bounceTarget ) { + handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget ); + } +} + +static gboolean handleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data) +{ + (void)widget; + gboolean handled = FALSE; + + if ( (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) { + if ( !popupMenu ) { + popupMenu = gtk_menu_new(); + GtkWidget* child = 0; + + //TRANSLATORS: An item in context menu on a colour in the swatches + child = gtk_menu_item_new_with_label(_("Set fill")); + g_signal_connect( G_OBJECT(child), + "activate", + G_CALLBACK(redirClick), + user_data); + gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); + + //TRANSLATORS: An item in context menu on a colour in the swatches + child = gtk_menu_item_new_with_label(_("Set stroke")); + + g_signal_connect( G_OBJECT(child), + "activate", + G_CALLBACK(redirSecondaryClick), + user_data); + gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); + + gtk_widget_show_all(popupMenu); + } + + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item ) { + bounceTarget = item; + if ( popupMenu ) { + gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time); + handled = TRUE; + } + } + } + + return handled; +} + +static void dieDieDie( GtkObject *obj, gpointer user_data ) +{ + g_message("die die die %p %p", obj, user_data ); +} + +//TODO: warning: deprecated conversion from string constant to ‘gchar*’ +// +//Turn out to be warnings that we should probably leave in place. The +// pointers/types used need to be read-only. So until we correct the using +// code, those warnings are actually desired. They say "Hey! Fix this". We +// definitely don't want to hide/ignore them. --JonCruz +static const GtkTargetEntry destColorTargets[] = { +#if ENABLE_MAGIC_COLORS +// {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID}, + {"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, +#endif // ENABLE_MAGIC_COLORS + {"application/x-color", 0, APP_X_COLOR}, +}; + +#include "color.h" // for SP_RGBA32_U_COMPOSE + +void ColorItem::_dropDataIn( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data) +{ + (void)widget; + (void)drag_context; + (void)x; + (void)y; + (void)event_time; +// g_message(" droppy droppy %d", info); + switch (info) { + case APP_X_INKY_COLOR: + { + if ( data->length >= 8 ) { + // Careful about endian issues. + guint16* dataVals = (guint16*)data->data; + if ( user_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item->def.isEditable() ) { + // Shove on in the new value + item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); + } + } + } + break; + } + case APP_X_COLOR: + { + if ( data->length == 8 ) { + // Careful about endian issues. + guint16* dataVals = (guint16*)data->data; +// { +// gchar c[64] = {0}; +// sp_svg_write_color( c, 64, +// SP_RGBA32_U_COMPOSE( +// 0x0ff & (dataVals[0] >> 8), +// 0x0ff & (dataVals[1] >> 8), +// 0x0ff & (dataVals[2] >> 8), +// 0xff // can't have transparency in the color itself +// //0x0ff & (data->data[3] >> 8), +// )); +// } + if ( user_data ) { + ColorItem* item = reinterpret_cast<ColorItem*>(user_data); + if ( item->def.isEditable() ) { + // Shove on in the new value + item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) ); + } + } + } + break; + } + default: + g_message("unknown drop type"); + } + +} + +static bool bruteForce( SPDocument* document, Inkscape::XML::Node* node, Glib::ustring const& match, int r, int g, int b ) +{ + bool changed = false; + + if ( node ) { + gchar const * val = node->attribute("inkscape:x-fill-tag"); + if ( val && (match == val) ) { + SPObject *obj = document->getObjectByRepr( node ); + + gchar c[64] = {0}; + sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, "fill", c ); + + sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); + ((SPItem*)obj)->updateRepr(); + + changed = true; + } + + val = node->attribute("inkscape:x-stroke-tag"); + if ( val && (match == val) ) { + SPObject *obj = document->getObjectByRepr( node ); + + gchar c[64] = {0}; + sp_svg_write_color( c, sizeof(c), SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) ); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, "stroke", c ); + + sp_desktop_apply_css_recursive( (SPItem*)obj, css, true ); + ((SPItem*)obj)->updateRepr(); + + changed = true; + } + + Inkscape::XML::Node* first = node->firstChild(); + changed |= bruteForce( document, first, match, r, g, b ); + + changed |= bruteForce( document, node->next(), match, r, g, b ); + } + + return changed; +} + +void ColorItem::_colorDefChanged(void* data) +{ + ColorItem* item = reinterpret_cast<ColorItem*>(data); + if ( item ) { + for ( std::vector<Gtk::Widget*>::iterator it = item->_previews.begin(); it != item->_previews.end(); ++it ) { + Gtk::Widget* widget = *it; + if ( IS_EEK_PREVIEW(widget->gobj()) ) { + EekPreview * preview = EEK_PREVIEW(widget->gobj()); + eek_preview_set_color( preview, + (item->def.getR() << 8) | item->def.getR(), + (item->def.getG() << 8) | item->def.getG(), + (item->def.getB() << 8) | item->def.getB() ); + + eek_preview_set_linked( preview, (LinkType)((item->_linkSrc ? PREVIEW_LINK_IN:0) + | (item->_listeners.empty() ? 0:PREVIEW_LINK_OUT) + | (item->_isLive ? PREVIEW_LINK_OTHER:0)) ); + + widget->queue_draw(); + } + } + + for ( std::vector<ColorItem*>::iterator it = item->_listeners.begin(); it != item->_listeners.end(); ++it ) { + guint r = item->def.getR(); + guint g = item->def.getG(); + guint b = item->def.getB(); + + if ( (*it)->_linkIsTone ) { + r = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * r) ) / 100; + g = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * g) ) / 100; + b = ( ((*it)->_linkPercent * (*it)->_linkGray) + ((100 - (*it)->_linkPercent) * b) ) / 100; + } else { + r = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * r) ) / 100; + g = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * g) ) / 100; + b = ( ((*it)->_linkPercent * 255) + ((100 - (*it)->_linkPercent) * b) ) / 100; + } + + (*it)->def.setRGB( r, g, b ); + } + + + // Look for objects using this color + { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if ( desktop ) { + SPDocument* document = sp_desktop_document( desktop ); + Inkscape::XML::Node *rroot = sp_document_repr_root( document ); + if ( rroot ) { + + // Find where this thing came from + Glib::ustring paletteName; + bool found = false; + int index = 0; + for ( std::vector<JustForNow*>::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) { + JustForNow* curr = *it2; + index = 0; + for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) { + if ( item == *zz ) { + found = true; + paletteName = curr->_name; + break; + } else { + index++; + } + } + } + + if ( !paletteName.empty() ) { + gchar* str = g_strdup_printf("%d|", index); + paletteName.insert( 0, str ); + g_free(str); + str = 0; + + if ( bruteForce( document, rroot, paletteName, item->def.getR(), item->def.getG(), item->def.getB() ) ) { + sp_document_done( document , SP_VERB_DIALOG_SWATCHES, + _("Change color definition")); + } + } + } + } + } + } +} + + +Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, ::PreviewSize size, guint ratio) +{ + Gtk::Widget* widget = 0; + if ( style == PREVIEW_STYLE_BLURB) { + Gtk::Label *lbl = new Gtk::Label(def.descr); + lbl->set_alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER); + widget = lbl; + } else { +// Glib::ustring blank(" "); +// if ( size == Inkscape::ICON_SIZE_MENU || size == Inkscape::ICON_SIZE_DECORATION ) { +// blank = " "; +// } + + GtkWidget* eekWidget = eek_preview_new(); + EekPreview * preview = EEK_PREVIEW(eekWidget); + Gtk::Widget* newBlot = Glib::wrap(eekWidget); + + eek_preview_set_color( preview, (def.getR() << 8) | def.getR(), (def.getG() << 8) | def.getG(), (def.getB() << 8) | def.getB()); + if ( _isRemove ) { + GError *error = NULL; + gchar *filepath = (gchar *) g_strdup_printf("%s/remove-color.png", INKSCAPE_PIXMAPDIR); + gsize bytesRead = 0; + gsize bytesWritten = 0; + gchar *localFilename = g_filename_from_utf8( filepath, + -1, + &bytesRead, + &bytesWritten, + &error); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(localFilename, &error); + if (!pixbuf) { + g_warning("Null pixbuf for %p [%s]", localFilename, localFilename ); + } + g_free(localFilename); + g_free(filepath); + + eek_preview_set_pixbuf( preview, pixbuf ); + } + + eek_preview_set_details( preview, (::PreviewStyle)style, (::ViewType)view, (::PreviewSize)size, ratio ); + eek_preview_set_linked( preview, (LinkType)((_linkSrc ? PREVIEW_LINK_IN:0) + | (_listeners.empty() ? 0:PREVIEW_LINK_OUT) + | (_isLive ? PREVIEW_LINK_OTHER:0)) ); + + def.addCallback( _colorDefChanged, this ); + + GValue val = {0, {{0}, {0}}}; + g_value_init( &val, G_TYPE_BOOLEAN ); + g_value_set_boolean( &val, FALSE ); + g_object_set_property( G_OBJECT(preview), "focus-on-click", &val ); + +/* + Gtk::Button *btn = new Gtk::Button(blank); + Gdk::Color color; + color.set_rgb((_r << 8)|_r, (_g << 8)|_g, (_b << 8)|_b); + btn->modify_bg(Gtk::STATE_NORMAL, color); + btn->modify_bg(Gtk::STATE_ACTIVE, color); + btn->modify_bg(Gtk::STATE_PRELIGHT, color); + btn->modify_bg(Gtk::STATE_SELECTED, color); + + Gtk::Widget* newBlot = btn; +*/ + + tips.set_tip((*newBlot), def.descr); + +/* + newBlot->signal_clicked().connect( sigc::mem_fun(*this, &ColorItem::buttonClicked) ); + + sigc::signal<void> type_signal_something; +*/ + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "clicked", + G_CALLBACK(handleClick), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "alt-clicked", + G_CALLBACK(handleSecondaryClick), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "button-press-event", + G_CALLBACK(handleButtonPress), + this); + + gtk_drag_source_set( GTK_WIDGET(newBlot->gobj()), + GDK_BUTTON1_MASK, + sourceColorEntries, + G_N_ELEMENTS(sourceColorEntries), + GdkDragAction(GDK_ACTION_MOVE | GDK_ACTION_COPY) ); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-data-get", + G_CALLBACK(ColorItem::_dragGetColorData), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-begin", + G_CALLBACK(dragBegin), + this ); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "enter-notify-event", + G_CALLBACK(handleEnterNotify), + this); + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "leave-notify-event", + G_CALLBACK(handleLeaveNotify), + this); + +// g_signal_connect( G_OBJECT(newBlot->gobj()), +// "drag-drop", +// G_CALLBACK(dragDropColorData), +// this); + + if ( def.isEditable() ) + { + gtk_drag_dest_set( GTK_WIDGET(newBlot->gobj()), + GTK_DEST_DEFAULT_ALL, + destColorTargets, + G_N_ELEMENTS(destColorTargets), + GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); + + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "drag-data-received", + G_CALLBACK(_dropDataIn), + this ); + } + + g_signal_connect( G_OBJECT(newBlot->gobj()), + "destroy", + G_CALLBACK(dieDieDie), + this); + + + widget = newBlot; + } + + _previews.push_back( widget ); + + return widget; +} + +void ColorItem::buttonClicked(bool secondary) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) return; + char const * attrName = secondary ? "stroke" : "fill"; + + gchar c[64]; + if (!_isRemove){ + guint32 rgba = (def.getR() << 24) | (def.getG() << 16) | (def.getB() << 8) | 0xff; + sp_svg_write_color(c, sizeof(c), rgba); + } + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, attrName, _isRemove ? "none" : c ); + sp_desktop_set_style(desktop, css); + sp_repr_css_attr_unref(css); + + if (_isRemove){ + sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, + secondary? _("Remove stroke color") : _("Remove fill color")); + } else { + sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, + secondary? _("Set stroke color from swatch") : _("Set fill color from swatch")); + } +} + +static char* trim( char* str ) { + char* ret = str; + while ( *str && (*str == ' ' || *str == '\t') ) { + str++; + } + ret = str; + while ( *str ) { + str++; + } + str--; + while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) { + *str-- = 0; + } + return ret; +} + +void skipWhitespace( char*& str ) { + while ( *str == ' ' || *str == '\t' ) { + str++; + } +} + +bool parseNum( char*& str, int& val ) { + val = 0; + while ( '0' <= *str && *str <= '9' ) { + val = val * 10 + (*str - '0'); + str++; + } + bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n'); + return retval; +} + + +static bool getBlock( std::string& dst, guchar ch, std::string const str ) +{ + bool good = false; + std::string::size_type pos = str.find(ch); + if ( pos != std::string::npos ) + { + std::string::size_type pos2 = str.find( '(', pos ); + if ( pos2 != std::string::npos ) { + std::string::size_type endPos = str.find( ')', pos2 ); + if ( endPos != std::string::npos ) { + dst = str.substr( pos2 + 1, (endPos - pos2 - 1) ); + good = true; + } + } + } + return good; +} + +static bool popVal( guint64& numVal, std::string& str ) +{ + bool good = false; + std::string::size_type endPos = str.find(','); + if ( endPos == std::string::npos ) { + endPos = str.length(); + } + + if ( endPos != std::string::npos && endPos > 0 ) { + std::string xxx = str.substr( 0, endPos ); + const gchar* ptr = xxx.c_str(); + gchar* endPtr = 0; + numVal = g_ascii_strtoull( ptr, &endPtr, 10 ); + if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { + // overflow + } else if ( (numVal == 0) && (endPtr == ptr) ) { + // failed conversion + } else { + good = true; + str.erase( 0, endPos + 1 ); + } + } + + return good; +} + +void ColorItem::_wireMagicColors( void* p ) +{ + JustForNow* onceMore = reinterpret_cast<JustForNow*>(p); + if ( onceMore ) + { + for ( std::vector<ColorItem*>::iterator it = onceMore->_colors.begin(); it != onceMore->_colors.end(); ++it ) + { + std::string::size_type pos = (*it)->def.descr.find("*{"); + if ( pos != std::string::npos ) + { + std::string subby = (*it)->def.descr.substr( pos + 2 ); + std::string::size_type endPos = subby.find("}*"); + if ( endPos != std::string::npos ) + { + subby.erase( endPos ); + //g_message("FOUND MAGIC at '%s'", (*it)->def.descr.c_str()); + //g_message(" '%s'", subby.c_str()); + + if ( subby.find('E') != std::string::npos ) + { + (*it)->def.setEditable( true ); + } + + if ( subby.find('L') != std::string::npos ) + { + (*it)->_isLive = true; + } + + std::string part; + // Tint. index + 1 more val. + if ( getBlock( part, 'T', subby ) ) { + guint64 colorIndex = 0; + if ( popVal( colorIndex, part ) ) { + guint64 percent = 0; + if ( popVal( percent, part ) ) { + (*it)->_linkTint( *(onceMore->_colors[colorIndex]), percent ); + } + } + } + + // Shade/tone. index + 1 or 2 more val. + if ( getBlock( part, 'S', subby ) ) { + guint64 colorIndex = 0; + if ( popVal( colorIndex, part ) ) { + guint64 percent = 0; + if ( popVal( percent, part ) ) { + guint64 grayLevel = 0; + if ( !popVal( grayLevel, part ) ) { + grayLevel = 0; + } + (*it)->_linkTone( *(onceMore->_colors[colorIndex]), percent, grayLevel ); + } + } + } + + } + } + } + } +} + + +void ColorItem::_linkTint( ColorItem& other, int percent ) +{ + if ( !_linkSrc ) + { + other._listeners.push_back(this); + _linkIsTone = false; + _linkPercent = percent; + if ( _linkPercent > 100 ) + _linkPercent = 100; + if ( _linkPercent < 0 ) + _linkPercent = 0; + _linkGray = 0; + _linkSrc = &other; + + ColorItem::_colorDefChanged(&other); + } +} + +void ColorItem::_linkTone( ColorItem& other, int percent, int grayLevel ) +{ + if ( !_linkSrc ) + { + other._listeners.push_back(this); + _linkIsTone = true; + _linkPercent = percent; + if ( _linkPercent > 100 ) + _linkPercent = 100; + if ( _linkPercent < 0 ) + _linkPercent = 0; + _linkGray = grayLevel; + _linkSrc = &other; + + ColorItem::_colorDefChanged(&other); + } +} + + +void _loadPaletteFile( gchar const *filename ) +{ + char block[1024]; + FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" ); + if ( f ) { + char* result = fgets( block, sizeof(block), f ); + if ( result ) { + if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) { + bool inHeader = true; + bool hasErr = false; + + JustForNow *onceMore = new JustForNow(); + + do { + result = fgets( block, sizeof(block), f ); + block[sizeof(block) - 1] = 0; + if ( result ) { + if ( block[0] == '#' ) { + // ignore comment + } else { + char *ptr = block; + // very simple check for header versus entry + while ( *ptr == ' ' || *ptr == '\t' ) { + ptr++; + } + if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) { + // blank line. skip it. + } else if ( '0' <= *ptr && *ptr <= '9' ) { + // should be an entry link + inHeader = false; + ptr = block; + Glib::ustring name(""); + int r = 0; + int g = 0; + int b = 0; + skipWhitespace(ptr); + if ( *ptr ) { + hasErr = parseNum(ptr, r); + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, g); + } + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, b); + } + if ( !hasErr && *ptr ) { + char* n = trim(ptr); + if (n != NULL) { + name = n; + } + } + if ( !hasErr ) { + // Add the entry now + Glib::ustring nameStr(name); + ColorItem* item = new ColorItem( r, g, b, nameStr ); + onceMore->_colors.push_back(item); + } + } else { + hasErr = true; + } + } else { + if ( !inHeader ) { + // Hmmm... probably bad. Not quite the format we want? + hasErr = true; + } else { + char* sep = strchr(result, ':'); + if ( sep ) { + *sep = 0; + char* val = trim(sep + 1); + char* name = trim(result); + if ( *name ) { + if ( strcmp( "Name", name ) == 0 ) + { + onceMore->_name = val; + } + else if ( strcmp( "Columns", name ) == 0 ) + { + gchar* endPtr = 0; + guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 ); + if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { + // overflow + } else if ( (numVal == 0) && (endPtr == val) ) { + // failed conversion + } else { + onceMore->_prefWidth = numVal; + } + } + } else { + // error + hasErr = true; + } + } else { + // error + hasErr = true; + } + } + } + } + } + } while ( result && !hasErr ); + if ( !hasErr ) { + possible.push_back(onceMore); +#if ENABLE_MAGIC_COLORS + ColorItem::_wireMagicColors( onceMore ); +#endif // ENABLE_MAGIC_COLORS + } else { + delete onceMore; + } + } + } + + fclose(f); + } +} + +static void loadEmUp() +{ + static bool beenHere = false; + if ( !beenHere ) { + beenHere = true; + + std::list<gchar *> sources; + sources.push_back( profile_path("palettes") ); + sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) ); + sources.push_back( g_strdup(CREATE_PALETTESDIR) ); + + // Use this loop to iterate through a list of possible document locations. + while (!sources.empty()) { + gchar *dirname = sources.front(); + + if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS ) + && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) { + GError *err = 0; + GDir *directory = g_dir_open(dirname, 0, &err); + if (!directory) { + gchar *safeDir = Inkscape::IO::sanitizeString(dirname); + g_warning(_("Palettes directory (%s) is unavailable."), safeDir); + g_free(safeDir); + } else { + gchar *filename = 0; + while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) { + gchar* lower = g_ascii_strdown( filename, -1 ); +// if ( g_str_has_suffix(lower, ".gpl") ) { + gchar* full = g_build_filename(dirname, filename, NULL); + if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) { + _loadPaletteFile(full); + } + g_free(full); +// } + g_free(lower); + } + g_dir_close(directory); + } + } + + // toss the dirname + g_free(dirname); + sources.pop_front(); + } + } +} + + + + + + + + + +SwatchesPanel& SwatchesPanel::getInstance() +{ + return *new SwatchesPanel(); +} + + +/** + * Constructor + */ +SwatchesPanel::SwatchesPanel(gchar const* prefsPath) : + Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true), + _holder(0) +{ + Gtk::RadioMenuItem* hotItem = 0; + _holder = new PreviewHolder(); + _remove = new ColorItem(); + loadEmUp(); + if ( !possible.empty() ) { + JustForNow* first = 0; + Glib::ustring targetName; + if ( !_prefs_path.empty() ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + targetName = prefs->getString(_prefs_path + "/palette"); + if (!targetName.empty()) { + for ( std::vector<JustForNow*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) { + if ( (*iter)->_name == targetName ) { + first = *iter; + break; + } + } + } + } + + if ( !first ) { + first = possible.front(); + } + + if ( first->_prefWidth > 0 ) { + _holder->setColumnPref( first->_prefWidth ); + } + _holder->freezeUpdates(); + _holder->addPreview(_remove); + for ( std::vector<ColorItem*>::iterator it = first->_colors.begin(); it != first->_colors.end(); it++ ) { + _holder->addPreview(*it); + } + _holder->thawUpdates(); + + Gtk::RadioMenuItem::Group groupOne; + + int i = 0; + for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end(); it++ ) { + JustForNow* curr = *it; + Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name)); + if ( curr == first ) { + hotItem = single; + } + _regItem( single, 3, i ); + i++; + } + } + + + _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET); + _setTargetFillable(_holder); + + show_all_children(); + + restorePanelPrefs(); + if ( hotItem ) { + hotItem->set_active(); + } +} + +SwatchesPanel::~SwatchesPanel() +{ + if (_remove) delete _remove; + if (_holder) delete _holder; +} + +void SwatchesPanel::setOrientation( Gtk::AnchorType how ) +{ + // Must call the parent class or bad things might happen + Inkscape::UI::Widget::Panel::setOrientation( how ); + + if ( _holder ) + { + _holder->setOrientation( Gtk::ANCHOR_SOUTH ); + } +} + +void SwatchesPanel::_handleAction( int setId, int itemId ) +{ + switch( setId ) { + case 3: + { + if ( itemId >= 0 && itemId < static_cast<int>(possible.size()) ) { + _holder->clear(); + JustForNow* curr = possible[itemId]; + + if ( !_prefs_path.empty() ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(_prefs_path + "/palette", curr->_name); + } + + if ( curr->_prefWidth > 0 ) { + _holder->setColumnPref( curr->_prefWidth ); + } + _holder->freezeUpdates(); + _holder->addPreview(_remove); + for ( std::vector<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) { + _holder->addPreview(*it); + } + _holder->thawUpdates(); + } + } + break; + } +} + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/swatches.h b/src/ui/dialog/swatches.h new file mode 100644 index 000000000..08fc9f79b --- /dev/null +++ b/src/ui/dialog/swatches.h @@ -0,0 +1,128 @@ +/** @file + * @brief Color swatches dialog + */ +/* Authors: + * Jon A. Cruz + * + * Copyright (C) 2005 Jon A. Cruz + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_DIALOGS_SWATCHES_H +#define SEEN_DIALOGS_SWATCHES_H + +#include <gtkmm/textview.h> +#include <gtkmm/tooltips.h> + +#include "ui/widget/panel.h" +#include "ui/previewholder.h" +#include "widgets/eek-color-def.h" + +using eek::ColorDef; + +namespace Inkscape { +namespace UI { +namespace Dialogs { + + +void _loadPaletteFile( gchar const *filename ); + +/** + * The color swatch you see on screen as a clickable box. + */ +class ColorItem : public Inkscape::UI::Previewable +{ + friend void _loadPaletteFile( gchar const *filename ); +public: + ColorItem(); + ColorItem( unsigned int r, unsigned int g, unsigned int b, + Glib::ustring& name ); + virtual ~ColorItem(); + ColorItem(ColorItem const &other); + virtual ColorItem &operator=(ColorItem const &other); + virtual Gtk::Widget* getPreview(PreviewStyle style, + ViewType view, + ::PreviewSize size, + guint ratio); + void buttonClicked(bool secondary = false); + bool isRemove(){ return _isRemove; } + ColorDef def; + +private: + static void _dropDataIn( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data); + + static void _dragGetColorData( GtkWidget *widget, + GdkDragContext *drag_context, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data); + + static void _wireMagicColors( void* p ); + static void _colorDefChanged(void* data); + + void _linkTint( ColorItem& other, int percent ); + void _linkTone( ColorItem& other, int percent, int grayLevel ); + + Gtk::Tooltips tips; + std::vector<Gtk::Widget*> _previews; + + bool _isRemove; + bool _isLive; + bool _linkIsTone; + int _linkPercent; + int _linkGray; + ColorItem* _linkSrc; + std::vector<ColorItem*> _listeners; +}; + +class RemoveColorItem; + +/** + * A panel that displays color swatches. + */ +class SwatchesPanel : public Inkscape::UI::Widget::Panel +{ +public: + SwatchesPanel(gchar const* prefsPath = "/dialogs/swatches"); + virtual ~SwatchesPanel(); + + static SwatchesPanel& getInstance(); + virtual void setOrientation( Gtk::AnchorType how ); + +protected: + virtual void _handleAction( int setId, int itemId ); + +private: + SwatchesPanel(SwatchesPanel const &); // no copy + SwatchesPanel &operator=(SwatchesPanel const &); // no assign + + static SwatchesPanel* instance; + + PreviewHolder* _holder; + ColorItem* _remove; +}; + +} //namespace Dialogs +} //namespace UI +} //namespace Inkscape + + + +#endif // SEEN_SWATCHES_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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/previewable.h b/src/ui/previewable.h index c517e4f28..ef1ca3ce2 100644 --- a/src/ui/previewable.h +++ b/src/ui/previewable.h @@ -14,7 +14,7 @@ #include <gtkmm/widget.h> -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/previewfillable.h b/src/ui/previewfillable.h index 6f02b60a8..f863af121 100644 --- a/src/ui/previewfillable.h +++ b/src/ui/previewfillable.h @@ -14,7 +14,7 @@ #include "previewable.h" -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/previewholder.h b/src/ui/previewholder.h index 812d4b27d..3c1a16195 100644 --- a/src/ui/previewholder.h +++ b/src/ui/previewholder.h @@ -17,7 +17,7 @@ #include <gtkmm/bin.h> #include <gtkmm/table.h> #include "previewfillable.h" -#include "../dialogs/eek-preview.h" +#include "../widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/ui/view/edit-widget.h b/src/ui/view/edit-widget.h index ea3205696..2bb708305 100644 --- a/src/ui/view/edit-widget.h +++ b/src/ui/view/edit-widget.h @@ -28,12 +28,12 @@ #include "ui/dialog/dialog-manager.h" #include "ui/view/edit-widget-interface.h" #include "ui/widget/dock.h" -#include "ui/widget/selected-style.h" +#include "ui/widget/layer-selector.h" #include "ui/widget/ruler.h" -#include "ui/widget/toolbox.h" +#include "ui/widget/selected-style.h" #include "ui/widget/svg-canvas.h" +#include "ui/widget/toolbox.h" #include "ui/widget/zoom-status.h" -#include "widgets/layer-selector.h" struct SPDesktop; struct SPDocument; diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 9b4048ea9..b6069631b 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -31,6 +31,8 @@ ink_common_sources += \ ui/widget/imagetoggler.h \ ui/widget/labelled.cpp \ ui/widget/labelled.h \ + ui/widget/layer-selector.cpp \ + ui/widget/layer-selector.h \ ui/widget/licensor.cpp \ ui/widget/licensor.h \ ui/widget/notebook-page.cpp \ diff --git a/src/ui/widget/entity-entry.cpp b/src/ui/widget/entity-entry.cpp index 980d225b2..e9f09f574 100644 --- a/src/ui/widget/entity-entry.cpp +++ b/src/ui/widget/entity-entry.cpp @@ -19,11 +19,9 @@ #include <gtkmm/scrolledwindow.h> #include <gtkmm/entry.h> -#include "ui/widget/registry.h" - -#include "dialogs/rdf.h" - #include "inkscape.h" +#include "rdf.h" +#include "ui/widget/registry.h" #include "entity-entry.h" diff --git a/src/ui/widget/layer-selector.cpp b/src/ui/widget/layer-selector.cpp new file mode 100644 index 000000000..51084b127 --- /dev/null +++ b/src/ui/widget/layer-selector.cpp @@ -0,0 +1,608 @@ +/* + * Inkscape::Widgets::LayerSelector - layer selector widget + * + * Authors: + * MenTaLguY <mental@rydia.net> + * + * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cstring> +#include <string> +#include <glibmm/i18n.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "document.h" +#include "layer-manager.h" +#include "sp-item.h" +#include "ui/dialog/layer-properties.h" +#include "ui/widget/layer-selector.h" +#include "util/filter-list.h" +#include "util/reverse-list.h" +#include "verbs.h" +#include "widgets/icon.h" +#include "widgets/shrink-wrap-button.h" +#include "xml/node-event-vector.h" + +namespace Inkscape { +namespace Widgets { + +namespace { + +class AlternateIcons : public Gtk::HBox { +public: + AlternateIcons(Inkscape::IconSize size, gchar const *a, gchar const *b) + : _a(NULL), _b(NULL) + { + if (a) { + _a = Gtk::manage(sp_icon_get_icon(a, size)); + _a->set_no_show_all(true); + add(*_a); + } + if (b) { + _b = Gtk::manage(sp_icon_get_icon(b, size)); + _b->set_no_show_all(true); + add(*_b); + } + setState(false); + } + + bool state() const { return _state; } + void setState(bool state) { + _state = state; + if (_state) { + if (_a) { + _a->hide(); + } + if (_b) { + _b->show(); + } + } else { + if (_a) { + _a->show(); + } + if (_b) { + _b->hide(); + } + } + } + +private: + Gtk::Widget *_a; + Gtk::Widget *_b; + bool _state; +}; + +} + +/** LayerSelector constructor. Creates lock and hide buttons, + * initalizes the layer dropdown selector with a label renderer, + * and hooks up signal for setting the desktop layer when the + * selector is changed. + */ +LayerSelector::LayerSelector(SPDesktop *desktop) +: _desktop(NULL), _layer(NULL) +{ + AlternateIcons *label; + + label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "visible", "hidden")); + _visibility_toggle.add(*label); + _visibility_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*label, &AlternateIcons::setState), + sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) + ) + ); + _visibility_toggled_connection = _visibility_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*this, &LayerSelector::_hideLayer), + sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) + ) + ); + + _visibility_toggle.set_relief(Gtk::RELIEF_NONE); + shrink_wrap_button(_visibility_toggle); + _tooltips.set_tip(_visibility_toggle, _("Toggle current layer visibility")); + pack_start(_visibility_toggle, Gtk::PACK_EXPAND_PADDING); + + label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "lock_unlocked", "width_height_lock")); + _lock_toggle.add(*label); + _lock_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*label, &AlternateIcons::setState), + sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) + ) + ); + _lock_toggled_connection = _lock_toggle.signal_toggled().connect( + sigc::compose( + sigc::mem_fun(*this, &LayerSelector::_lockLayer), + sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) + ) + ); + + _lock_toggle.set_relief(Gtk::RELIEF_NONE); + shrink_wrap_button(_lock_toggle); + _tooltips.set_tip(_lock_toggle, _("Lock or unlock current layer")); + pack_start(_lock_toggle, Gtk::PACK_EXPAND_PADDING); + + _tooltips.set_tip(_selector, _("Current layer")); + pack_start(_selector, Gtk::PACK_EXPAND_WIDGET); + + _layer_model = Gtk::ListStore::create(_model_columns); + _selector.set_model(_layer_model); + _selector.pack_start(_label_renderer); + _selector.set_cell_data_func( + _label_renderer, + sigc::mem_fun(*this, &LayerSelector::_prepareLabelRenderer) + ); + + _selection_changed_connection = _selector.signal_changed().connect( + sigc::mem_fun(*this, &LayerSelector::_setDesktopLayer) + ); + setDesktop(desktop); +} + +/** Destructor - disconnects signal handler + */ +LayerSelector::~LayerSelector() { + setDesktop(NULL); + _selection_changed_connection.disconnect(); +} + +namespace { + +/** Helper function - detaches desktop from selector + */ +bool detach(LayerSelector *selector) { + selector->setDesktop(NULL); + return FALSE; +} + +} + +/** Sets the desktop for the widget. First disconnects signals + * for the current desktop, then stores the pointer to the + * given \a desktop, and attaches its signals to this one. + * Then it selects the current layer for the desktop. + */ +void LayerSelector::setDesktop(SPDesktop *desktop) { + if ( desktop == _desktop ) { + return; + } + + if (_desktop) { +// _desktop_shutdown_connection.disconnect(); + _layer_changed_connection.disconnect(); +// g_signal_handlers_disconnect_by_func(_desktop, (gpointer)&detach, this); + } + _desktop = desktop; + if (_desktop) { + // TODO we need a different signal for this, really..s +// _desktop_shutdown_connection = _desktop->connectShutdown( +// sigc::bind (sigc::ptr_fun (detach), this)); +// g_signal_connect_after(_desktop, "shutdown", GCallback(detach), this); + + _layer_changed_connection = _desktop->connectCurrentLayerChanged( + sigc::mem_fun(*this, &LayerSelector::_selectLayer) + ); + _selectLayer(_desktop->currentLayer()); + } +} + +namespace { + +class is_layer { +public: + is_layer(SPDesktop *desktop) : _desktop(desktop) {} + bool operator()(SPObject &object) const { + return _desktop->isLayer(&object); + } +private: + SPDesktop *_desktop; +}; + +class column_matches_object { +public: + column_matches_object(Gtk::TreeModelColumn<SPObject *> const &column, + SPObject &object) + : _column(column), _object(object) {} + bool operator()(Gtk::TreeModel::const_iterator const &iter) const { + SPObject *current=(*iter)[_column]; + return current == &_object; + } +private: + Gtk::TreeModelColumn<SPObject *> const &_column; + SPObject &_object; +}; + +} + +/** Selects the given layer in the dropdown selector. + */ +void LayerSelector::_selectLayer(SPObject *layer) { + using Inkscape::Util::List; + using Inkscape::Util::cons; + using Inkscape::Util::reverse_list; + + _selection_changed_connection.block(); + + while (!_layer_model->children().empty()) { + Gtk::ListStore::iterator first_row(_layer_model->children().begin()); + _destroyEntry(first_row); + _layer_model->erase(first_row); + } + + SPObject *root=_desktop->currentRoot(); + + if (_layer) { + sp_object_unref(_layer, NULL); + _layer = NULL; + } + + if (layer) { + List<SPObject &> hierarchy=reverse_list<SPObject::ParentIterator>(layer, root); + if ( layer == root ) { + _buildEntries(0, cons(*root, hierarchy)); + } else if (hierarchy) { + _buildSiblingEntries(0, *root, hierarchy); + } + + Gtk::TreeIter row( + std::find_if( + _layer_model->children().begin(), + _layer_model->children().end(), + column_matches_object(_model_columns.object, *layer) + ) + ); + if ( row != _layer_model->children().end() ) { + _selector.set_active(row); + } + + _layer = layer; + sp_object_ref(_layer, NULL); + } + + if ( !layer || layer == root ) { + _visibility_toggle.set_sensitive(false); + _visibility_toggle.set_active(false); + _lock_toggle.set_sensitive(false); + _lock_toggle.set_active(false); + } else { + _visibility_toggle.set_sensitive(true); + _visibility_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false )); + _lock_toggle.set_sensitive(true); + _lock_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false )); + } + + _selection_changed_connection.unblock(); +} + +/** Sets the current desktop layer to the actively selected layer. + */ +void LayerSelector::_setDesktopLayer() { + Gtk::ListStore::iterator selected(_selector.get_active()); + SPObject *layer=_selector.get_active()->get_value(_model_columns.object); + if ( _desktop && layer ) { + _layer_changed_connection.block(); + + _desktop->layer_manager->setCurrentLayer(layer); + + _layer_changed_connection.unblock(); + + _selectLayer(_desktop->currentLayer()); + } + if (_desktop && _desktop->canvas) { + gtk_widget_grab_focus (GTK_WIDGET(_desktop->canvas)); + } +} + +/** Creates rows in the _layer_model data structure for each item + * in \a hierarchy, to a given \a depth. + */ +void LayerSelector::_buildEntries(unsigned depth, + Inkscape::Util::List<SPObject &> hierarchy) +{ + using Inkscape::Util::List; + using Inkscape::Util::rest; + + _buildEntry(depth, *hierarchy); + + List<SPObject &> remainder=rest(hierarchy); + if (remainder) { + _buildEntries(depth+1, remainder); + } else { + _buildSiblingEntries(depth+1, *hierarchy, remainder); + } +} + +/** Creates entries in the _layer_model data structure for + * all siblings of the first child in \a parent. + */ +void LayerSelector::_buildSiblingEntries( + unsigned depth, SPObject &parent, + Inkscape::Util::List<SPObject &> hierarchy +) { + using Inkscape::Util::List; + using Inkscape::Util::rest; + using Inkscape::Util::reverse_list_in_place; + using Inkscape::Util::filter_list; + + Inkscape::Util::List<SPObject &> siblings( + reverse_list_in_place( + filter_list<SPObject::SiblingIterator>( + is_layer(_desktop), parent.firstChild(), NULL + ) + ) + ); + + SPObject *layer( hierarchy ? &*hierarchy : NULL ); + + while (siblings) { + _buildEntry(depth, *siblings); + if ( &*siblings == layer ) { + _buildSiblingEntries(depth+1, *layer, rest(hierarchy)); + } + ++siblings; + } +} + +namespace { + +struct Callbacks { + sigc::slot<void> update_row; + sigc::slot<void> update_list; +}; + +void attribute_changed(Inkscape::XML::Node */*repr*/, gchar const *name, + gchar const */*old_value*/, gchar const */*new_value*/, + bool /*is_interactive*/, void *data) +{ + if ( !std::strcmp(name, "inkscape:groupmode") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } else { + reinterpret_cast<Callbacks *>(data)->update_row(); + } +} + +void node_added(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void node_removed(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void node_reordered(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, + Inkscape::XML::Node */*old_ref*/, Inkscape::XML::Node */*new_ref*/, + void *data) +{ + gchar const *mode=child->attribute("inkscape:groupmode"); + if ( mode && !std::strcmp(mode, "layer") ) { + reinterpret_cast<Callbacks *>(data)->update_list(); + } +} + +void update_row_for_object(SPObject *object, + Gtk::TreeModelColumn<SPObject *> const &column, + Glib::RefPtr<Gtk::ListStore> const &model) +{ + Gtk::TreeIter row( + std::find_if( + model->children().begin(), + model->children().end(), + column_matches_object(column, *object) + ) + ); + if ( row != model->children().end() ) { + model->row_changed(model->get_path(row), row); + } +} + +void rebuild_all_rows(sigc::slot<void, SPObject *> rebuild, SPDesktop *desktop) +{ + rebuild(desktop->currentLayer()); +} + +} + +void LayerSelector::_protectUpdate(sigc::slot<void> slot) { + bool visibility_blocked=_visibility_toggled_connection.blocked(); + bool lock_blocked=_lock_toggled_connection.blocked(); + _visibility_toggled_connection.block(true); + _lock_toggled_connection.block(true); + slot(); + + SPObject *layer = _desktop ? _desktop->currentLayer() : 0; + if ( layer ) { + bool wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false ); + if ( _lock_toggle.get_active() != wantedValue ) { + _lock_toggle.set_active( wantedValue ); + } + wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false ); + if ( _visibility_toggle.get_active() != wantedValue ) { + _visibility_toggle.set_active( wantedValue ); + } + } + _visibility_toggled_connection.block(visibility_blocked); + _lock_toggled_connection.block(lock_blocked); +} + +/** Builds and appends a row in the layer model object. + */ +void LayerSelector::_buildEntry(unsigned depth, SPObject &object) { + Inkscape::XML::NodeEventVector *vector; + + Callbacks *callbacks=new Callbacks(); + + callbacks->update_row = sigc::bind( + sigc::mem_fun(*this, &LayerSelector::_protectUpdate), + sigc::bind( + sigc::ptr_fun(&update_row_for_object), + &object, _model_columns.object, _layer_model + ) + ); + + SPObject *layer=_desktop->currentLayer(); + if ( &object == layer || &object == SP_OBJECT_PARENT(layer) ) { + callbacks->update_list = sigc::bind( + sigc::mem_fun(*this, &LayerSelector::_protectUpdate), + sigc::bind( + sigc::ptr_fun(&rebuild_all_rows), + sigc::mem_fun(*this, &LayerSelector::_selectLayer), + _desktop + ) + ); + + Inkscape::XML::NodeEventVector events = { + &node_added, + &node_removed, + &attribute_changed, + NULL, + &node_reordered + }; + + vector = new Inkscape::XML::NodeEventVector(events); + } else { + Inkscape::XML::NodeEventVector events = { + NULL, + NULL, + &attribute_changed, + NULL, + NULL + }; + + vector = new Inkscape::XML::NodeEventVector(events); + } + + Gtk::ListStore::iterator row(_layer_model->append()); + + row->set_value(_model_columns.depth, depth); + + sp_object_ref(&object, NULL); + row->set_value(_model_columns.object, &object); + + Inkscape::GC::anchor(SP_OBJECT_REPR(&object)); + row->set_value(_model_columns.repr, SP_OBJECT_REPR(&object)); + + row->set_value(_model_columns.callbacks, reinterpret_cast<void *>(callbacks)); + + sp_repr_add_listener(SP_OBJECT_REPR(&object), vector, callbacks); +} + +/** Removes a row from the _model_columns object, disconnecting listeners + * on the slot. + */ +void LayerSelector::_destroyEntry(Gtk::ListStore::iterator const &row) { + Callbacks *callbacks=reinterpret_cast<Callbacks *>(row->get_value(_model_columns.callbacks)); + SPObject *object=row->get_value(_model_columns.object); + if (object) { + sp_object_unref(object, NULL); + } + Inkscape::XML::Node *repr=row->get_value(_model_columns.repr); + if (repr) { + sp_repr_remove_listener_by_data(repr, callbacks); + Inkscape::GC::release(repr); + } + delete callbacks; +} + +/** Formats the label for a given layer row + */ +void LayerSelector::_prepareLabelRenderer( + Gtk::TreeModel::const_iterator const &row +) { + unsigned depth=(*row)[_model_columns.depth]; + SPObject *object=(*row)[_model_columns.object]; + bool label_defaulted(false); + + // TODO: when the currently selected row is removed, + // (or before one has been selected) something appears to + // "invent" an iterator with null data and try to render it; + // where does it come from, and how can we avoid it? + if ( object && SP_OBJECT_REPR(object) ) { + SPObject *layer=( _desktop ? _desktop->currentLayer() : NULL ); + SPObject *root=( _desktop ? _desktop->currentRoot() : NULL ); + + bool isancestor = !( (layer && (SP_OBJECT_PARENT(object) == SP_OBJECT_PARENT(layer))) || ((layer == root) && (SP_OBJECT_PARENT(object) == root))); + + bool iscurrent = ( object == layer && object != root ); + + gchar *format = g_strdup_printf ( + "<span size=\"smaller\" %s><tt>%*s%s</tt>%s%s%s%%s%s%s%s</span>", + ( _desktop && _desktop->itemIsHidden (SP_ITEM(object)) ? "foreground=\"gray50\"" : "" ), + depth, "", ( iscurrent ? "•" : " " ), + ( iscurrent ? "<b>" : "" ), + ( SP_ITEM(object)->isLocked() ? "[" : "" ), + ( isancestor ? "<small>" : "" ), + ( isancestor ? "</small>" : "" ), + ( SP_ITEM(object)->isLocked() ? "]" : "" ), + ( iscurrent ? "</b>" : "" ) + ); + + gchar const *label; + if ( object != root ) { + label = object->label(); + if (!label) { + label = object->defaultLabel(); + label_defaulted = true; + } + } else { + label = _("(root)"); + } + + gchar *text = g_markup_printf_escaped(format, label); + _label_renderer.property_markup() = text; + g_free(text); + g_free(format); + } else { + _label_renderer.property_markup() = "<small> </small>"; + } + + _label_renderer.property_ypad() = 1; + _label_renderer.property_style() = ( label_defaulted ? + Pango::STYLE_ITALIC : + Pango::STYLE_NORMAL ); +} + +void LayerSelector::_lockLayer(bool lock) { + if ( _layer && SP_IS_ITEM(_layer) ) { + SP_ITEM(_layer)->setLocked(lock); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, + lock? _("Lock layer") : _("Unlock layer")); + } +} + +void LayerSelector::_hideLayer(bool hide) { + if ( _layer && SP_IS_ITEM(_layer) ) { + SP_ITEM(_layer)->setHidden(hide); + sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, + hide? _("Hide layer") : _("Unhide layer")); + } +} + +} +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/layer-selector.h b/src/ui/widget/layer-selector.h new file mode 100644 index 000000000..0b5300272 --- /dev/null +++ b/src/ui/widget/layer-selector.h @@ -0,0 +1,110 @@ +/* + * Inkscape::Widgets::LayerSelector - layer selector widget + * + * Authors: + * MenTaLguY <mental@rydia.net> + * + * Copyright (C) 2004 MenTaLguY + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR +#define SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR + +#include <gtkmm/box.h> +#include <gtkmm/combobox.h> +#include <gtkmm/togglebutton.h> +#include <gtkmm/tooltips.h> +#include <gtkmm/cellrenderertext.h> +#include <gtkmm/treemodel.h> +#include <gtkmm/liststore.h> +#include <sigc++/slot.h> +#include "util/list.h" + +class SPDesktop; +class SPDocument; +class SPObject; +namespace Inkscape { +namespace XML { +class Node; +} +} + + +namespace Inkscape { +namespace Widgets { + +class DocumentTreeModel; + +class LayerSelector : public Gtk::HBox { +public: + LayerSelector(SPDesktop *desktop = NULL); + ~LayerSelector(); + + SPDesktop *desktop() { return _desktop; } + void setDesktop(SPDesktop *desktop); + +private: + class LayerModelColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn<unsigned> depth; + Gtk::TreeModelColumn<SPObject *> object; + Gtk::TreeModelColumn<Inkscape::XML::Node *> repr; + Gtk::TreeModelColumn<void *> callbacks; + + LayerModelColumns() { + add(depth); add(object); add(repr); add(callbacks); + } + }; + + SPDesktop *_desktop; + + Gtk::Tooltips _tooltips; + Gtk::ComboBox _selector; + Gtk::ToggleButton _visibility_toggle; + Gtk::ToggleButton _lock_toggle; + + LayerModelColumns _model_columns; + Gtk::CellRendererText _label_renderer; + Glib::RefPtr<Gtk::ListStore> _layer_model; + +// sigc::connection _desktop_shutdown_connection; + sigc::connection _layer_changed_connection; + sigc::connection _selection_changed_connection; + sigc::connection _visibility_toggled_connection; + sigc::connection _lock_toggled_connection; + + SPObject *_layer; + + void _selectLayer(SPObject *layer); + void _setDesktopLayer(); + + void _buildEntry(unsigned depth, SPObject &object); + void _buildEntries(unsigned depth, + Inkscape::Util::List<SPObject &> hierarchy); + void _buildSiblingEntries(unsigned depth, + SPObject &parent, + Inkscape::Util::List<SPObject &> hierarchy); + void _protectUpdate(sigc::slot<void> slot); + void _destroyEntry(Gtk::ListStore::iterator const &row); + void _hideLayer(bool hide); + void _lockLayer(bool lock); + + void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); +}; + +} +} + +#endif +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/licensor.cpp b/src/ui/widget/licensor.cpp index 24bd5595f..05f00edfc 100644 --- a/src/ui/widget/licensor.cpp +++ b/src/ui/widget/licensor.cpp @@ -20,7 +20,7 @@ #include "ui/widget/entity-entry.h" #include "ui/widget/registry.h" -#include "dialogs/rdf.h" +#include "rdf.h" #include "inkscape.h" #include "licensor.h" diff --git a/src/ui/widget/panel.cpp b/src/ui/widget/panel.cpp index 9811cc89c..82f75c3ff 100644 --- a/src/ui/widget/panel.cpp +++ b/src/ui/widget/panel.cpp @@ -29,7 +29,7 @@ #include "preferences.h" #include "desktop-handles.h" #include "inkscape.h" -#include "dialogs/eek-preview.h" +#include "widgets/eek-preview.h" namespace Inkscape { namespace UI { diff --git a/src/unclump.cpp b/src/unclump.cpp new file mode 100644 index 000000000..aebcfd908 --- /dev/null +++ b/src/unclump.cpp @@ -0,0 +1,388 @@ +/** @file + * @brief Unclumping objects + */ +/* Authors: + * bulia byak + * + * Copyright (C) 2005 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <algorithm> +#include <map> +#include "sp-item.h" + + +// Taking bbox of an item is an expensive operation, and we need to do it many times, so here we +// cache the centers, widths, and heights of items + +//FIXME: make a class with these cashes as members instead of globals +std::map<const gchar *, Geom::Point> c_cache; +std::map<const gchar *, Geom::Point> wh_cache; + +/** +Center of bbox of item +*/ +Geom::Point +unclump_center (SPItem *item) +{ + std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(item)); + if ( i != c_cache.end() ) { + return i->second; + } + + Geom::OptRect r = item->getBounds(sp_item_i2d_affine(item)); + if (r) { + Geom::Point const c = r->midpoint(); + c_cache[SP_OBJECT_ID(item)] = c; + return c; + } else { + // FIXME + return Geom::Point(0, 0); + } +} + +Geom::Point +unclump_wh (SPItem *item) +{ + Geom::Point wh; + std::map<const gchar *, Geom::Point>::iterator i = wh_cache.find(SP_OBJECT_ID(item)); + if ( i != wh_cache.end() ) { + wh = i->second; + } else { + Geom::OptRect r = item->getBounds(sp_item_i2d_affine(item)); + if (r) { + wh = r->dimensions(); + wh_cache[SP_OBJECT_ID(item)] = wh; + } else { + wh = Geom::Point(0, 0); + } + } + + return wh; +} + +/** +Distance between "edges" of item1 and item2. An item is considered to be an ellipse inscribed into its w/h, +so its radius (distance from center to edge) depends on the w/h and the angle towards the other item. +May be negative if the edge of item1 is between the center and the edge of item2. +*/ +double +unclump_dist (SPItem *item1, SPItem *item2) +{ + Geom::Point c1 = unclump_center (item1); + Geom::Point c2 = unclump_center (item2); + + Geom::Point wh1 = unclump_wh (item1); + Geom::Point wh2 = unclump_wh (item2); + + // angle from each item's center to the other's, unsqueezed by its w/h, normalized to 0..pi/2 + double a1 = atan2 ((c2 - c1)[Geom::Y], (c2 - c1)[Geom::X] * wh1[Geom::Y]/wh1[Geom::X]); + a1 = fabs (a1); + if (a1 > M_PI/2) a1 = M_PI - a1; + + double a2 = atan2 ((c1 - c2)[Geom::Y], (c1 - c2)[Geom::X] * wh2[Geom::Y]/wh2[Geom::X]); + a2 = fabs (a2); + if (a2 > M_PI/2) a2 = M_PI - a2; + + // get the radius of each item for the given angle + double r1 = 0.5 * (wh1[Geom::X] + (wh1[Geom::Y] - wh1[Geom::X]) * (a1/(M_PI/2))); + double r2 = 0.5 * (wh2[Geom::X] + (wh2[Geom::Y] - wh2[Geom::X]) * (a2/(M_PI/2))); + + // dist between centers minus angle-adjusted radii + double dist_r = (Geom::L2 (c2 - c1) - r1 - r2); + + double stretch1 = wh1[Geom::Y]/wh1[Geom::X]; + double stretch2 = wh2[Geom::Y]/wh2[Geom::X]; + + if ((stretch1 > 1.5 || stretch1 < 0.66) && (stretch2 > 1.5 || stretch2 < 0.66)) { + + std::vector<double> dists; + dists.push_back (dist_r); + + // If both objects are not circle-like, find dists between four corners + std::vector<Geom::Point> c1_points(2); + { + double y_closest; + if (c2[Geom::Y] > c1[Geom::Y] + wh1[Geom::Y]/2) { + y_closest = c1[Geom::Y] + wh1[Geom::Y]/2; + } else if (c2[Geom::Y] < c1[Geom::Y] - wh1[Geom::Y]/2) { + y_closest = c1[Geom::Y] - wh1[Geom::Y]/2; + } else { + y_closest = c2[Geom::Y]; + } + c1_points[0] = Geom::Point (c1[Geom::X], y_closest); + double x_closest; + if (c2[Geom::X] > c1[Geom::X] + wh1[Geom::X]/2) { + x_closest = c1[Geom::X] + wh1[Geom::X]/2; + } else if (c2[Geom::X] < c1[Geom::X] - wh1[Geom::X]/2) { + x_closest = c1[Geom::X] - wh1[Geom::X]/2; + } else { + x_closest = c2[Geom::X]; + } + c1_points[1] = Geom::Point (x_closest, c1[Geom::Y]); + } + + + std::vector<Geom::Point> c2_points(2); + { + double y_closest; + if (c1[Geom::Y] > c2[Geom::Y] + wh2[Geom::Y]/2) { + y_closest = c2[Geom::Y] + wh2[Geom::Y]/2; + } else if (c1[Geom::Y] < c2[Geom::Y] - wh2[Geom::Y]/2) { + y_closest = c2[Geom::Y] - wh2[Geom::Y]/2; + } else { + y_closest = c1[Geom::Y]; + } + c2_points[0] = Geom::Point (c2[Geom::X], y_closest); + double x_closest; + if (c1[Geom::X] > c2[Geom::X] + wh2[Geom::X]/2) { + x_closest = c2[Geom::X] + wh2[Geom::X]/2; + } else if (c1[Geom::X] < c2[Geom::X] - wh2[Geom::X]/2) { + x_closest = c2[Geom::X] - wh2[Geom::X]/2; + } else { + x_closest = c1[Geom::X]; + } + c2_points[1] = Geom::Point (x_closest, c2[Geom::Y]); + } + + for (int i = 0; i < 2; i ++) { + for (int j = 0; j < 2; j ++) { + dists.push_back (Geom::L2 (c1_points[i] - c2_points[j])); + } + } + + // return the minimum of all dists + return *std::min_element(dists.begin(), dists.end()); + } else { + return dist_r; + } +} + +/** +Average unclump_dist from item to others +*/ +double unclump_average (SPItem *item, GSList *others) +{ + int n = 0; + double sum = 0; + + for (GSList *i = others; i != NULL; i = i->next) { + SPItem *other = SP_ITEM (i->data); + + if (other == item) + continue; + + n++; + sum += unclump_dist (item, other); + } + + if (n != 0) + return sum/n; + else + return 0; +} + +/** +Closest to item among others + */ +SPItem *unclump_closest (SPItem *item, GSList *others) +{ + double min = HUGE_VAL; + SPItem *closest = NULL; + + for (GSList *i = others; i != NULL; i = i->next) { + SPItem *other = SP_ITEM (i->data); + + if (other == item) + continue; + + double dist = unclump_dist (item, other); + if (dist < min && fabs (dist) < 1e6) { + min = dist; + closest = other; + } + } + + return closest; +} + +/** +Most distant from item among others + */ +SPItem *unclump_farest (SPItem *item, GSList *others) +{ + double max = -HUGE_VAL; + SPItem *farest = NULL; + + for (GSList *i = others; i != NULL; i = i->next) { + SPItem *other = SP_ITEM (i->data); + + if (other == item) + continue; + + double dist = unclump_dist (item, other); + if (dist > max && fabs (dist) < 1e6) { + max = dist; + farest = other; + } + } + + return farest; +} + +/** +Removes from the \a rest list those items that are "behind" \a closest as seen from \a item, +i.e. those on the other side of the line through \a closest perpendicular to the direction from \a +item to \a closest. Returns a newly created list which must be freed. + */ +GSList * +unclump_remove_behind (SPItem *item, SPItem *closest, GSList *rest) +{ + Geom::Point it = unclump_center (item); + Geom::Point p1 = unclump_center (closest); + + // perpendicular through closest to the direction to item: + Geom::Point perp = Geom::rot90(it - p1); + Geom::Point p2 = p1 + perp; + + // get the standard Ax + By + C = 0 form for p1-p2: + double A = p1[Geom::Y] - p2[Geom::Y]; + double B = p2[Geom::X] - p1[Geom::X]; + double C = p2[Geom::Y] * p1[Geom::X] - p1[Geom::Y] * p2[Geom::X]; + + // substitute the item into it: + double val_item = A * it[Geom::X] + B * it[Geom::Y] + C; + + GSList *out = NULL; + + for (GSList *i = rest; i != NULL; i = i->next) { + SPItem *other = SP_ITEM (i->data); + + if (other == item) + continue; + + Geom::Point o = unclump_center (other); + double val_other = A * o[Geom::X] + B * o[Geom::Y] + C; + + if (val_item * val_other <= 1e-6) { + // different signs, which means item and other are on the different sides of p1-p2 line; skip + } else { + out = g_slist_prepend (out, other); + } + } + + return out; +} + +/** +Moves \a what away from \a from by \a dist + */ +void +unclump_push (SPItem *from, SPItem *what, double dist) +{ + Geom::Point it = unclump_center (what); + Geom::Point p = unclump_center (from); + Geom::Point by = dist * Geom::unit_vector (- (p - it)); + + Geom::Matrix move = Geom::Translate (by); + + std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(what)); + if ( i != c_cache.end() ) { + i->second *= move; + } + + //g_print ("push %s at %g,%g from %g,%g by %g,%g, dist %g\n", SP_OBJECT_ID(what), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); + + sp_item_set_i2d_affine(what, sp_item_i2d_affine(what) * move); + sp_item_write_transform(what, SP_OBJECT_REPR(what), what->transform, NULL); +} + +/** +Moves \a what towards \a to by \a dist + */ +void +unclump_pull (SPItem *to, SPItem *what, double dist) +{ + Geom::Point it = unclump_center (what); + Geom::Point p = unclump_center (to); + Geom::Point by = dist * Geom::unit_vector (p - it); + + Geom::Matrix move = Geom::Translate (by); + + std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(SP_OBJECT_ID(what)); + if ( i != c_cache.end() ) { + i->second *= move; + } + + //g_print ("pull %s at %g,%g to %g,%g by %g,%g, dist %g\n", SP_OBJECT_ID(what), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); + + sp_item_set_i2d_affine(what, sp_item_i2d_affine(what) * move); + sp_item_write_transform(what, SP_OBJECT_REPR(what), what->transform, NULL); +} + + +/** +Unclumps the items in \a items, reducing local unevenness in their distribution. Produces an effect +similar to "engraver dots". The only distribution which is unchanged by unclumping is a hexagonal +grid. May be called repeatedly for stronger effect. + */ +void +unclump (GSList *items) +{ + c_cache.clear(); + wh_cache.clear(); + + for (GSList *i = items; i != NULL; i = i->next) { // for each original/clone x: + SPItem *item = SP_ITEM (i->data); + + GSList *nei = NULL; + + GSList *rest = g_slist_copy (items); + rest = g_slist_remove (rest, item); + + while (rest != NULL) { + SPItem *closest = unclump_closest (item, rest); + if (closest) { + nei = g_slist_prepend (nei, closest); + rest = g_slist_remove (rest, closest); + GSList *new_rest = unclump_remove_behind (item, closest, rest); + g_slist_free (rest); + rest = new_rest; + } else { + g_slist_free (rest); + break; + } + } + + if (g_slist_length (nei) >= 2) { + double ave = unclump_average (item, nei); + + SPItem *closest = unclump_closest (item, nei); + SPItem *farest = unclump_farest (item, nei); + + double dist_closest = unclump_dist (closest, item); + double dist_farest = unclump_dist (farest, item); + + //g_print ("NEI %d for item %s closest %s at %g farest %s at %g ave %g\n", g_slist_length(nei), SP_OBJECT_ID(item), SP_OBJECT_ID(closest), dist_closest, SP_OBJECT_ID(farest), dist_farest, ave); + + if (fabs (ave) < 1e6 && fabs (dist_closest) < 1e6 && fabs (dist_farest) < 1e6) { // otherwise the items are bogus + // increase these coefficients to make unclumping more aggressive and less stable + // the pull coefficient is a bit bigger to counteract the long-term expansion trend + unclump_push (closest, item, 0.3 * (ave - dist_closest)); + unclump_pull (farest, item, 0.35 * (dist_farest - ave)); + } + } + } +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/unclump.h b/src/unclump.h new file mode 100644 index 000000000..c5a8bf7d7 --- /dev/null +++ b/src/unclump.h @@ -0,0 +1,29 @@ +/** @file + * @brief Unclumping objects + */ +/* Authors: + * bulia byak + * + * Copyright (C) 2005 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_DIALOGS_UNCLUMP_H +#define SEEN_DIALOGS_UNCLUMP_H + +#include <glib/gslist.h> + +void unclump(GSList *items); + +#endif /* !UNCLUMP_H_SEEN */ + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/verbs.cpp b/src/verbs.cpp index ce624b14c..834e1511d 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -38,15 +38,10 @@ #include "desktop.h" #include "desktop-handles.h" #include "dialogs/clonetiler.h" -#include "dialogs/extensions.h" #include "dialogs/find.h" -#include "dialogs/iconpreview.h" #include "dialogs/input.h" #include "dialogs/item-properties.h" -#include "dialogs/layer-properties.h" -#include "dialogs/layers-panel.h" #include "dialogs/spellcheck.h" -#include "dialogs/swatches.h" #include "dialogs/text-edit.h" #include "dialogs/xml-tree.h" #include "display/curve.h" @@ -78,7 +73,12 @@ #include "tools-switch.h" #include "ui/dialog/dialog-manager.h" #include "ui/dialog/document-properties.h" +#include "ui/dialog/extensions.h" +#include "ui/dialog/icon-preview.h" #include "ui/dialog/inkscape-preferences.h" +#include "ui/dialog/layer-properties.h" +#include "ui/dialog/layers.h" +#include "ui/dialog/swatches.h" #include "ui/icon-names.h" #ifdef WITH_INKBOARD diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 32a8a71e5..13f2b33eb 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -3,12 +3,16 @@ ink_common_sources += \ widgets/button.cpp \ widgets/button.h \ - widgets/calligraphic-profile-rename.cpp \ - widgets/calligraphic-profile-rename.h \ widgets/dash-selector.cpp \ widgets/dash-selector.h \ widgets/desktop-widget.cpp \ widgets/desktop-widget.h \ + widgets/eek-color-def.cpp \ + widgets/eek-color-def.h \ + widgets/eek-preview.cpp \ + widgets/eek-preview.h \ + widgets/fill-style.cpp \ + widgets/fill-style.h \ widgets/font-selector.cpp \ widgets/font-selector.h \ widgets/gradient-image.cpp \ @@ -21,8 +25,6 @@ ink_common_sources += \ widgets/gradient-vector.h \ widgets/icon.cpp \ widgets/icon.h \ - widgets/layer-selector.cpp \ - widgets/layer-selector.h \ widgets/paint-selector.cpp \ widgets/paint-selector.h \ widgets/ruler.cpp \ @@ -31,6 +33,8 @@ ink_common_sources += \ widgets/select-toolbar.h \ widgets/shrink-wrap-button.cpp \ widgets/shrink-wrap-button.h \ + widgets/sp-attribute-widget.cpp \ + widgets/sp-attribute-widget.h \ widgets/sp-color-gtkselector.cpp \ widgets/sp-color-gtkselector.h \ widgets/sp-color-icc-selector.cpp \ @@ -61,6 +65,8 @@ ink_common_sources += \ widgets/sp-xmlview-content.h \ widgets/sp-xmlview-tree.cpp \ widgets/sp-xmlview-tree.h \ + widgets/stroke-style.cpp \ + widgets/stroke-style.h \ widgets/toolbox.cpp \ widgets/toolbox.h \ widgets/widget-sizes.h diff --git a/src/widgets/calligraphic-profile-rename.cpp b/src/widgets/calligraphic-profile-rename.cpp deleted file mode 100644 index 888b327f4..000000000 --- a/src/widgets/calligraphic-profile-rename.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/** @file - * @brief Dialog for naming calligraphic profiles - * - * @note This file is in the wrong directory because of link order issues - - * it is required by widgets/toolbox.cpp, and libspwidgets.a comes after - * libinkdialogs.a in the current link order. - */ -/* Author: - * Aubanel MONNIER - * - * Copyright (C) 2007 Authors - * Released under GNU GPL. Read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <glibmm/i18n.h> -#include <gtkmm/stock.h> - -#include "desktop.h" -#include "calligraphic-profile-rename.h" - -namespace Inkscape { -namespace UI { -namespace Dialog { - -CalligraphicProfileRename::CalligraphicProfileRename() : - _applied(false) -{ - Gtk::VBox *mainVBox = get_vbox(); - _layout_table.set_spacings(4); - _layout_table.resize (1, 2); - - _profile_name_entry.set_activates_default(true); - - _profile_name_label.set_label(_("Profile name:")); - _profile_name_label.set_alignment(1.0, 0.5); - - _layout_table.attach(_profile_name_label, - 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); - _layout_table.attach(_profile_name_entry, - 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL); - mainVBox->pack_start(_layout_table, false, false, 4); - // Buttons - _close_button.set_use_stock(true); - _close_button.set_label(Gtk::Stock::CANCEL.id); - _close_button.set_flags(Gtk::CAN_DEFAULT); - - _apply_button.set_use_underline(true); - _apply_button.set_label(_("Save")); - _apply_button.set_flags(Gtk::CAN_DEFAULT); - - _close_button.signal_clicked() - .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)); - _apply_button.signal_clicked() - .connect(sigc::mem_fun(*this, &CalligraphicProfileRename::_apply)); - - signal_delete_event().connect( sigc::bind_return( - sigc::hide(sigc::mem_fun(*this, &CalligraphicProfileRename::_close)), true ) ); - - add_action_widget(_close_button, Gtk::RESPONSE_CLOSE); - add_action_widget(_apply_button, Gtk::RESPONSE_APPLY); - - _apply_button.grab_default(); - - show_all_children(); -} - -void CalligraphicProfileRename::_apply() -{ - _profile_name = _profile_name_entry.get_text(); - _applied = true; - _close(); -} - -void CalligraphicProfileRename::_close() -{ - this->Gtk::Dialog::hide(); -} - -void CalligraphicProfileRename::show(SPDesktop *desktop) -{ - CalligraphicProfileRename &dial = instance(); - dial._applied=false; - dial.set_modal(true); - desktop->setWindowTransient (dial.gobj()); - dial.property_destroy_with_parent() = true; - // dial.Gtk::Dialog::show(); - //dial.present(); - dial.run(); -} - -} // namespace Dialog -} // namespace UI -} // namespace Inkscape - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/calligraphic-profile-rename.h b/src/widgets/calligraphic-profile-rename.h deleted file mode 100644 index 53ce907ed..000000000 --- a/src/widgets/calligraphic-profile-rename.h +++ /dev/null @@ -1,75 +0,0 @@ -/** @file - * @brief Dialog for naming calligraphic profiles - */ -/* Author: - * Aubanel MONNIER - * - * Copyright (C) 2007 Authors - * Released under GNU GPL. Read the file 'COPYING' for more information - */ - -#ifndef INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H -#define INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_H - -#include <gtkmm/dialog.h> -#include <gtkmm/entry.h> -#include <gtkmm/label.h> -#include <gtkmm/table.h> -struct SPDesktop; - -namespace Inkscape { -namespace UI { -namespace Dialog { - -class CalligraphicProfileRename : public Gtk::Dialog { -public: - CalligraphicProfileRename(); - virtual ~CalligraphicProfileRename() {} - Glib::ustring getName() const { - return "CalligraphicProfileRename"; - } - - static void show(SPDesktop *desktop); - static bool applied() { - return instance()._applied; - } - static Glib::ustring getProfileName() { - return instance()._profile_name; - } - -protected: - void _close(); - void _apply(); - - Gtk::Label _profile_name_label; - Gtk::Entry _profile_name_entry; - Gtk::Table _layout_table; - Gtk::Button _close_button; - Gtk::Button _apply_button; - Glib::ustring _profile_name; - bool _applied; -private: - static CalligraphicProfileRename &instance() { - static CalligraphicProfileRename instance_; - return instance_; - } - CalligraphicProfileRename(CalligraphicProfileRename const &); // no copy - CalligraphicProfileRename &operator=(CalligraphicProfileRename const &); // no assign -}; - -} // namespace Dialog -} // namespace UI -} // namespace Inkscape - -#endif // INKSCAPE_DIALOG_CALLIGRAPHIC_PROFILE_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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 324e5b008..356a09418 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -27,39 +27,39 @@ #include <gtkmm/paned.h> #include <gtk/gtk.h> -#include "macros.h" -#include "inkscape-private.h" -#include "desktop-handles.h" +#include "box3d-context.h" +#include "color-profile-fns.h" +#include "conn-avoid-ref.h" #include "desktop-events.h" -#include "document.h" +#include "desktop-handles.h" #include "desktop-widget.h" -#include "sp-namedview.h" -#include "interface.h" -#include "toolbox.h" -#include "preferences.h" -#include "file.h" #include "display/canvas-arena.h" #include "display/nr-arena.h" +#include "document.h" +#include "ege-color-prof-tracker.h" +#include "ege-select-one-action.h" #include <extension/db.h> +#include "file.h" #include "helper/units.h" +#include "inkscape-private.h" +#include "interface.h" +#include "macros.h" +#include "preferences.h" +#include "sp-image.h" +#include "sp-item.h" +#include "sp-namedview.h" +#include "toolbox.h" +#include "ui/dialog/dialog-manager.h" +#include "ui/dialog/swatches.h" +#include "ui/widget/dock.h" +#include "ui/widget/layer-selector.h" +#include "ui/widget/selected-style.h" #include "widgets/button.h" #include "widgets/ruler.h" -#include "widgets/widget-sizes.h" -#include "widgets/spw-utilities.h" #include "widgets/spinbutton-events.h" -#include "widgets/layer-selector.h" +#include "widgets/spw-utilities.h" #include "widgets/toolbox.h" -#include "ui/dialog/dialog-manager.h" -#include "ui/widget/dock.h" -#include "ui/widget/selected-style.h" -#include "sp-item.h" -#include "dialogs/swatches.h" -#include "conn-avoid-ref.h" -#include "ege-select-one-action.h" -#include "ege-color-prof-tracker.h" -#include "color-profile-fns.h" -#include "box3d-context.h" -#include "sp-image.h" +#include "widgets/widget-sizes.h" #if defined (SOLARIS) && (SOLARIS == 8) #include "round.h" diff --git a/src/widgets/eek-color-def.cpp b/src/widgets/eek-color-def.cpp new file mode 100644 index 000000000..85b00b251 --- /dev/null +++ b/src/widgets/eek-color-def.cpp @@ -0,0 +1,147 @@ +/** @file + * @brief EEK color definition + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Eek Color Definition. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "config.h" + +#ifdef HAVE_LIBINTL_H +#include <libintl.h> +#endif + +#if !defined(_) +#define _(s) gettext(s) +#endif // !defined(_) + +#include "eek-color-def.h" + +namespace eek +{ + +ColorDef::ColorDef() : + descr(_("none")), + r(0), + g(0), + b(0), + none(true), + editable(false) +{ +} + +ColorDef::ColorDef( unsigned int r, unsigned int g, unsigned int b, const std::string& description ) : + descr(description), + r(r), + g(g), + b(b), + none(false), + editable(false) +{ +} + +ColorDef::~ColorDef() +{ +} + +ColorDef::ColorDef( ColorDef const &other ) +{ + if ( this != &other ) { + *this = other; + } +} + +ColorDef& ColorDef::operator=( ColorDef const &other ) +{ + if ( this != & other ) + { + r = other.r; + g = other.g; + b = other.b; + descr = other.descr; + none = other.none; + editable = other.editable; + } + return *this; +} + +class ColorDef::HookData { +public: + HookData( ColorCallback cb, void* data ) {_cb = cb; _data = data;} + ColorCallback _cb; + void* _data; +}; + +void ColorDef::setRGB( unsigned int r, unsigned int g, unsigned int b ) +{ + if ( r != this->r || g != this->g || b != this->b ) { + this->r = r; + this->g = g; + this->b = b; + + // beware of callbacks changing things + for ( std::vector<HookData*>::iterator it = _listeners.begin(); it != _listeners.end(); ++it ) + { + if ( (*it)->_cb ) + { + (*it)->_cb( (*it)->_data ); + } + } + } +} + +void ColorDef::addCallback( ColorCallback cb, void* data ) +{ + _listeners.push_back( new HookData(cb, data) ); +} + +void ColorDef::removeCallback( ColorCallback cb, void* data ) +{ + (void)cb; + (void)data; +} + +} // namespace eek + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/eek-color-def.h b/src/widgets/eek-color-def.h new file mode 100644 index 000000000..63cd096be --- /dev/null +++ b/src/widgets/eek-color-def.h @@ -0,0 +1,102 @@ +/** @file + * @brief EEK color definition + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Eek Color Definition. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef SEEN_EEK_COLOR_DEF_H +#define SEEN_EEK_COLOR_DEF_H + +#include <string> +#include <vector> + +namespace eek +{ + +typedef void (*ColorCallback)( void* data ); + + +class ColorDef +{ +public: + ColorDef(); + ColorDef( unsigned int r, unsigned int g, unsigned int b, const std::string& description ); + virtual ~ColorDef(); + + ColorDef( ColorDef const &other ); + virtual ColorDef& operator=( ColorDef const &other ); + + void setRGB( unsigned int r, unsigned int g, unsigned int b ); + unsigned int getR() const { return r; } + unsigned int getG() const { return g; } + unsigned int getB() const { return b; } + + void addCallback( ColorCallback cb, void* data ); + void removeCallback( ColorCallback cb, void* data ); + + bool isEditable() const { return editable; } + void setEditable( bool edit ) { editable = edit; } + + std::string descr; + +protected: + unsigned int r; + unsigned int g; + unsigned int b; + bool none; + bool editable; + +private: + class HookData; + + std::vector<HookData*> _listeners; +}; + + +} // namespace eek + +#endif // SEEN_EEK_COLOR_DEF_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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/eek-preview.cpp b/src/widgets/eek-preview.cpp new file mode 100644 index 000000000..1c1adf543 --- /dev/null +++ b/src/widgets/eek-preview.cpp @@ -0,0 +1,736 @@ +/** @file + * @brief EEK preview stuff + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Eek Preview Stuffs. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtk/gtk.h> +#include "eek-preview.h" + +#define PRIME_BUTTON_MAGIC_NUMBER 1 + +#define FOCUS_PROP_ID 1 + +/* Keep in sycn with last value in eek-preview.h */ +#define PREVIEW_SIZE_LAST PREVIEW_SIZE_HUGE +#define PREVIEW_SIZE_NEXTFREE (PREVIEW_SIZE_HUGE + 1) + +#define PREVIEW_MAX_RATIO 500 + +static void eek_preview_class_init( EekPreviewClass *klass ); +static void eek_preview_init( EekPreview *preview ); + +static GtkWidgetClass* parent_class = 0; + +void eek_preview_set_color( EekPreview* preview, int r, int g, int b ) +{ + preview->_r = r; + preview->_g = g; + preview->_b = b; + + gtk_widget_queue_draw(GTK_WIDGET(preview)); +} + + +void eek_preview_set_pixbuf( EekPreview* preview, GdkPixbuf* pixbuf ) +{ + preview->_previewPixbuf = pixbuf; + + gtk_widget_queue_draw(GTK_WIDGET(preview)); + + if (preview->_scaled) { + g_object_unref(preview->_scaled); + preview->_scaled = 0; + } + preview->_scaledW = gdk_pixbuf_get_width(preview->_previewPixbuf); + preview->_scaledH = gdk_pixbuf_get_height(preview->_previewPixbuf); +} + + +GType eek_preview_get_type(void) +{ + static GType preview_type = 0; + + if (!preview_type) { + static const GTypeInfo preview_info = { + sizeof( EekPreviewClass ), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc)eek_preview_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof( EekPreview ), + 0, /* n_preallocs */ + (GInstanceInitFunc)eek_preview_init, + NULL /* value_table */ + }; + + + preview_type = g_type_register_static( GTK_TYPE_DRAWING_AREA, "EekPreview", &preview_info, (GTypeFlags)0 ); + } + + return preview_type; +} + +static gboolean setupDone = FALSE; +static GtkRequisition sizeThings[PREVIEW_SIZE_NEXTFREE]; + +void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes ) +{ + gint width = 0; + gint height = 0; + gint smallest = 512; + gint largest = 0; + guint i = 0; + guint delta = 0; + + for ( i = 0; i < count; ++i ) { + gboolean worked = gtk_icon_size_lookup( sizes[i], &width, &height ); + if ( worked ) { + if ( width < smallest ) { + smallest = width; + } + if ( width > largest ) { + largest = width; + } + } + } + + smallest = (smallest * 3) / 4; + + delta = largest - smallest; + + for ( i = 0; i < G_N_ELEMENTS(sizeThings); ++i ) { + guint val = smallest + ( (i * delta) / (G_N_ELEMENTS(sizeThings) - 1) ); + sizeThings[i].width = val; + sizeThings[i].height = val; + } + + setupDone = TRUE; +} + +static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req ) +{ + gint width = 0; + gint height = 0; + EekPreview* preview = EEK_PREVIEW(widget); + + if ( !setupDone ) { + GtkIconSize sizes[] = { + GTK_ICON_SIZE_MENU, + GTK_ICON_SIZE_SMALL_TOOLBAR, + GTK_ICON_SIZE_LARGE_TOOLBAR, + GTK_ICON_SIZE_BUTTON, + GTK_ICON_SIZE_DIALOG + }; + eek_preview_set_size_mappings( G_N_ELEMENTS(sizes), sizes ); + } + + width = sizeThings[preview->_size].width; + height = sizeThings[preview->_size].height; + + if ( preview->_view == VIEW_TYPE_LIST ) { + width *= 3; + } + + if ( preview->_ratio != 100 ) { + width = (width * preview->_ratio) / 100; + if ( width < 0 ) { + width = 1; + } + } + + req->width = width; + req->height = height; +} + +enum { + CLICKED_SIGNAL, + ALTCLICKED_SIGNAL, + LAST_SIGNAL +}; + + +static guint eek_preview_signals[LAST_SIGNAL] = { 0 }; + + +gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event ) +{ +/* g_message("Exposed!!! %s", GTK_WIDGET_HAS_FOCUS(widget) ? "XXX" : "---" ); */ + gint insetX = 0; + gint insetY = 0; + + (void)event; +/* + gint lower = widget->allocation.width; + lower = (widget->allocation.height < lower) ? widget->allocation.height : lower; + if ( lower > 16 ) { + insetX++; + if ( lower > 18 ) { + insetX++; + if ( lower > 22 ) { + insetX++; + if ( lower > 24 ) { + insetX++; + if ( lower > 32 ) { + insetX++; + } + } + } + } + insetY = insetX; + } +*/ + + if ( GTK_WIDGET_DRAWABLE( widget ) ) { + GtkStyle* style = gtk_widget_get_style( widget ); + + if ( insetX > 0 || insetY > 0 ) { + gtk_paint_flat_box( style, + widget->window, + (GtkStateType)GTK_WIDGET_STATE(widget), + GTK_SHADOW_NONE, + NULL, + widget, + NULL, + 0, 0, + widget->allocation.width, widget->allocation.height); + } + + GdkGC *gc = gdk_gc_new( widget->window ); + EekPreview* preview = EEK_PREVIEW(widget); + GdkColor fg = {0, preview->_r, preview->_g, preview->_b}; + + gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE ); + + gdk_gc_set_foreground( gc, &fg ); + + gdk_draw_rectangle( widget->window, + gc, + TRUE, + insetX, insetY, + widget->allocation.width - (insetX * 2), widget->allocation.height - (insetY * 2) ); + + if ( preview->_linked ) { + /* Draw arrow */ + GdkRectangle possible = {insetX, insetY, (widget->allocation.width - (insetX * 2)), (widget->allocation.height - (insetY * 2)) }; + GdkRectangle area = {possible.x, possible.y, possible.width / 2, possible.height / 2 }; + + /* Make it square */ + if ( area.width > area.height ) + area.width = area.height; + if ( area.height > area.width ) + area.height = area.width; + + /* Center it horizontally */ + if ( area.width < possible.width ) { + int diff = (possible.width - area.width) / 2; + area.x += diff; + } + + + if ( preview->_linked & PREVIEW_LINK_IN ) { + gtk_paint_arrow( style, + widget->window, + (GtkStateType)widget->state, + GTK_SHADOW_ETCHED_IN, + NULL, /* clip area. &area, */ + widget, /* may be NULL */ + NULL, /* detail */ + GTK_ARROW_DOWN, + FALSE, + area.x, area.y, + area.width, area.height + ); + } + + if ( preview->_linked & PREVIEW_LINK_OUT ) { + GdkRectangle otherArea = {area.x, area.y, area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height); + } + + gtk_paint_arrow( style, + widget->window, + (GtkStateType)widget->state, + GTK_SHADOW_ETCHED_OUT, + NULL, /* clip area. &area, */ + widget, /* may be NULL */ + NULL, /* detail */ + GTK_ARROW_UP, + FALSE, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height + ); + } + + if ( preview->_linked & PREVIEW_LINK_OTHER ) { + GdkRectangle otherArea = {insetX, area.y, area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } + + gtk_paint_arrow( style, + widget->window, + (GtkStateType)widget->state, + GTK_SHADOW_ETCHED_OUT, + NULL, /* clip area. &area, */ + widget, /* may be NULL */ + NULL, /* detail */ + GTK_ARROW_LEFT, + FALSE, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height + ); + } + } + + if ( preview->_previewPixbuf ) { + GtkDrawingArea* da = &(preview->drawing); + GdkDrawable* drawable = (GdkDrawable*) (((GtkWidget*)da)->window); + gint w = 0; + gint h = 0; + gdk_drawable_get_size(drawable, &w, &h); + if ((w != preview->_scaledW) || (h != preview->_scaledH)) { + if (preview->_scaled) { + g_object_unref(preview->_scaled); + } + preview->_scaled = gdk_pixbuf_scale_simple(preview->_previewPixbuf, w, h, GDK_INTERP_BILINEAR); + preview->_scaledW = w; + preview->_scaledH = h; + } + + GdkPixbuf* pix = (preview->_scaled) ? preview->_scaled : preview->_previewPixbuf; + gdk_draw_pixbuf( drawable, 0, pix, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0 ); + } + + + if ( GTK_WIDGET_HAS_FOCUS(widget) ) { + gtk_paint_focus( style, + widget->window, + GTK_STATE_NORMAL, + NULL, /* GdkRectangle *area, */ + widget, + NULL, + 0 + 1, 0 + 1, + widget->allocation.width - 2, widget->allocation.height - 2 ); + } + } + + + return FALSE; +} + + +static gboolean eek_preview_enter_cb( GtkWidget* widget, GdkEventCrossing* event ) +{ + if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { + EekPreview* preview = EEK_PREVIEW(widget); + preview->_within = TRUE; + gtk_widget_set_state( widget, preview->_hot ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT ); + } + return FALSE; +} + +static gboolean eek_preview_leave_cb( GtkWidget* widget, GdkEventCrossing* event ) +{ + if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { + EekPreview* preview = EEK_PREVIEW(widget); + preview->_within = FALSE; + gtk_widget_set_state( widget, GTK_STATE_NORMAL ); + } + return FALSE; +} + +/* +static gboolean eek_preview_focus_in_event( GtkWidget* widget, GdkEventFocus* event ) +{ + g_message("focus IN"); + gboolean blip = parent_class->focus_in_event ? parent_class->focus_in_event(widget, event) : FALSE; + return blip; +} + +static gboolean eek_preview_focus_out_event( GtkWidget* widget, GdkEventFocus* event ) +{ + g_message("focus OUT"); + gboolean blip = parent_class->focus_out_event ? parent_class->focus_out_event(widget, event) : FALSE; + return blip; +} +*/ + +static gboolean eek_preview_button_press_cb( GtkWidget* widget, GdkEventButton* event ) +{ + if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { + EekPreview* preview = EEK_PREVIEW(widget); + + if ( preview->_takesFocus && !GTK_WIDGET_HAS_FOCUS(widget) ) { + gtk_widget_grab_focus(widget); + } + + if ( event->button == PRIME_BUTTON_MAGIC_NUMBER ) { + preview->_hot = TRUE; + if ( preview->_within ) { + gtk_widget_set_state( widget, GTK_STATE_ACTIVE ); + } + } + } + + return FALSE; +} + +static gboolean eek_preview_button_release_cb( GtkWidget* widget, GdkEventButton* event ) +{ + if ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) { + EekPreview* preview = EEK_PREVIEW(widget); + preview->_hot = FALSE; + gtk_widget_set_state( widget, GTK_STATE_NORMAL ); + if ( preview->_within && event->button == PRIME_BUTTON_MAGIC_NUMBER ) { + gboolean isAlt = (event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK; + + if ( isAlt ) { + g_signal_emit( widget, eek_preview_signals[ALTCLICKED_SIGNAL], 0, 2 ); + } else { + g_signal_emit( widget, eek_preview_signals[CLICKED_SIGNAL], 0 ); + } + } + } + return FALSE; +} + +gboolean eek_preview_key_press_event( GtkWidget* widget, GdkEventKey* event) +{ + (void)widget; + (void)event; + g_message("TICK"); + return FALSE; +} + +gboolean eek_preview_key_release_event( GtkWidget* widget, GdkEventKey* event) +{ + (void)widget; + (void)event; + g_message("tock"); + return FALSE; +} + +static void eek_preview_get_property( GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class); + switch ( property_id ) { + case FOCUS_PROP_ID: + { + EekPreview* preview = EEK_PREVIEW( object ); + g_value_set_boolean( value, preview->_takesFocus ); + } + break; + default: + { + if ( gobjClass->get_property ) { + gobjClass->get_property( object, property_id, value, pspec ); + } + } + } +} + +static void eek_preview_set_property( GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GObjectClass* gobjClass = G_OBJECT_CLASS(parent_class); + switch ( property_id ) { + case FOCUS_PROP_ID: + { + EekPreview* preview = EEK_PREVIEW( object ); + gboolean val = g_value_get_boolean( value ); + if ( val != preview->_takesFocus ) { + preview->_takesFocus = val; + } + } + break; + default: + { + if ( gobjClass->set_property ) { + gobjClass->set_property( object, property_id, value, pspec ); + } + } + } +} + + +static gboolean eek_preview_popup_menu( GtkWidget* widget ) +{ +/* g_message("Do the popup!"); */ + gboolean blip = parent_class->popup_menu ? parent_class->popup_menu(widget) : FALSE; + return blip; +} + + +static void eek_preview_class_init( EekPreviewClass *klass ) +{ + GObjectClass* gobjClass = G_OBJECT_CLASS(klass); + /*GtkObjectClass* objectClass = (GtkObjectClass*)klass;*/ + GtkWidgetClass* widgetClass = (GtkWidgetClass*)klass; + + gobjClass->set_property = eek_preview_set_property; + gobjClass->get_property = eek_preview_get_property; + + /*objectClass->destroy = eek_preview_destroy;*/ + + parent_class = (GtkWidgetClass*)g_type_class_peek_parent( klass ); + + /*widgetClass->map = ;*/ + /*widgetClass->unmap = ;*/ + /*widgetClass->realize = ;*/ + /*widgetClass->unrealize = ;*/ + widgetClass->size_request = eek_preview_size_request; + /*widgetClass->size_allocate = ;*/ + /*widgetClass->state_changed = ;*/ + /*widgetClass->style_set = ;*/ + /*widgetClass->grab_notify = ;*/ + + widgetClass->button_press_event = eek_preview_button_press_cb; + widgetClass->button_release_event = eek_preview_button_release_cb; + /*widgetClass->delete_event = ;*/ + /*widgetClass->destroy_event = ;*/ + widgetClass->expose_event = eek_preview_expose_event; +/* widgetClass->key_press_event = eek_preview_key_press_event; */ +/* widgetClass->key_release_event = eek_preview_key_release_event; */ + widgetClass->enter_notify_event = eek_preview_enter_cb; + widgetClass->leave_notify_event = eek_preview_leave_cb; + /*widgetClass->configure_event = ;*/ + /*widgetClass->focus_in_event = eek_preview_focus_in_event;*/ + /*widgetClass->focus_out_event = eek_preview_focus_out_event;*/ + + /* selection */ + /*widgetClass->selection_get = ;*/ + /*widgetClass->selection_received = ;*/ + + + /* drag source: */ + /*widgetClass->drag_begin = ;*/ + /*widgetClass->drag_end = ;*/ + /*widgetClass->drag_data_get = ;*/ + /*widgetClass->drag_data_delete = ;*/ + + /* drag target: */ + /*widgetClass->drag_leave = ;*/ + /*widgetClass->drag_motion = ;*/ + /*widgetClass->drag_drop = ;*/ + /*widgetClass->drag_data_received = ;*/ + + /* For keybindings: */ + widgetClass->popup_menu = eek_preview_popup_menu; + /*widgetClass->show_help = ;*/ + + /* Accessibility support: */ + /*widgetClass->get_accessible = ;*/ + /*widgetClass->screen_changed = ;*/ + /*widgetClass->can_activate_accel = ;*/ + + + eek_preview_signals[CLICKED_SIGNAL] = + g_signal_new( "clicked", + G_TYPE_FROM_CLASS( klass ), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET( EekPreviewClass, clicked ), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); + + eek_preview_signals[ALTCLICKED_SIGNAL] = + g_signal_new( "alt-clicked", + G_TYPE_FROM_CLASS( klass ), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET( EekPreviewClass, clicked ), + NULL, NULL, + g_cclosure_marshal_VOID__INT, G_TYPE_NONE, + 1, G_TYPE_INT ); + + + g_object_class_install_property( gobjClass, + FOCUS_PROP_ID, + g_param_spec_boolean( + "focus-on-click", + NULL, + "flag to grab focus when clicked", + TRUE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT) + ) + ); +} + +void eek_preview_set_linked( EekPreview* splat, LinkType link ) +{ + link = (LinkType)(link & PREVIEW_LINK_ALL); + if ( link != (LinkType)splat->_linked ) { + splat->_linked = link; + + gtk_widget_queue_draw( GTK_WIDGET(splat) ); + } +} + +LinkType eek_preview_get_linked( EekPreview* splat ) +{ + return (LinkType)splat->_linked; +} + +gboolean eek_preview_get_focus_on_click( EekPreview* preview ) +{ + return preview->_takesFocus; +} + +void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click ) +{ + if ( focus_on_click != preview->_takesFocus ) { + preview->_takesFocus = focus_on_click; + } +} + +void eek_preview_set_details( EekPreview* preview, PreviewStyle prevstyle, ViewType view, PreviewSize size, guint ratio ) +{ + preview->_prevstyle = prevstyle; + preview->_view = view; + + if ( size > PREVIEW_SIZE_LAST ) { + size = PREVIEW_SIZE_LAST; + } + preview->_size = size; + + if ( ratio > PREVIEW_MAX_RATIO ) { + ratio = PREVIEW_MAX_RATIO; + } + preview->_ratio = ratio; + + gtk_widget_queue_draw(GTK_WIDGET(preview)); +} + +static void eek_preview_init( EekPreview *preview ) +{ + GtkWidget* widg = GTK_WIDGET(preview); + GTK_WIDGET_SET_FLAGS( widg, GTK_CAN_FOCUS ); + GTK_WIDGET_SET_FLAGS( widg, GTK_RECEIVES_DEFAULT ); + + gtk_widget_set_sensitive( widg, TRUE ); + + gtk_widget_add_events(widg, GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK + | GDK_FOCUS_CHANGE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK ); + +/* gtk_widget_add_events( widg, GDK_ALL_EVENTS_MASK );*/ + + preview->_r = 0x80; + preview->_g = 0x80; + preview->_b = 0xcc; + preview->_scaledW = 0; + preview->_scaledH = 0; + + preview->_hot = FALSE; + preview->_within = FALSE; + preview->_takesFocus = FALSE; + + preview->_prevstyle = PREVIEW_STYLE_ICON; + preview->_view = VIEW_TYPE_LIST; + preview->_size = PREVIEW_SIZE_SMALL; + preview->_ratio = 100; + + preview->_previewPixbuf = 0; + preview->_scaled = 0; + +/* + GdkColor color = {0}; + color.red = (255 << 8) | 255; + + GdkColor whack = {0}; + whack.green = (255 << 8) | 255; + + gtk_widget_modify_bg( widg, GTK_STATE_NORMAL, &color ); + gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &whack ); +*/ + +/* GTK_STATE_ACTIVE, */ +/* GTK_STATE_PRELIGHT, */ +/* GTK_STATE_SELECTED, */ +/* GTK_STATE_INSENSITIVE */ + + if ( 0 ) { + GdkColor color = {0,0,0,0}; + + color.red = 0xffff; + color.green = 0; + color.blue = 0xffff; + gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); + gtk_widget_modify_bg(widg, GTK_STATE_ACTIVE, &color); + + color.red = 0; + color.green = 0xffff; + color.blue = 0; + gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); + gtk_widget_modify_bg(widg, GTK_STATE_SELECTED, &color); + + color.red = 0xffff; + color.green = 0; + color.blue = 0; + gdk_colormap_alloc_color( gdk_colormap_get_system(), &color, FALSE, TRUE ); + gtk_widget_modify_bg( widg, GTK_STATE_PRELIGHT, &color ); + } +} + + +GtkWidget* eek_preview_new(void) +{ + return GTK_WIDGET( g_object_new( EEK_PREVIEW_TYPE, NULL ) ); +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/eek-preview.h b/src/widgets/eek-preview.h new file mode 100644 index 000000000..6eb5c8930 --- /dev/null +++ b/src/widgets/eek-preview.h @@ -0,0 +1,152 @@ +/** @file + * @brief EEK preview stuff + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Eek Preview Stuffs. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2005-2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef SEEN_EEK_PREVIEW_H +#define SEEN_EEK_PREVIEW_H + +#include <gdk/gdkpixbuf.h> +#include <gtk/gtkdrawingarea.h> + +G_BEGIN_DECLS + + +#define EEK_PREVIEW_TYPE (eek_preview_get_type()) +#define EEK_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST( (obj), EEK_PREVIEW_TYPE, EekPreview)) +#define EEK_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST( (klass), EEK_PREVIEW_TYPE, EekPreviewClass)) +#define IS_EEK_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE( (obj), EEK_PREVIEW_TYPE)) +#define IS_EEK_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE( (klass), EEK_PREVIEW_TYPE)) +#define EEK_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS( (obj), EEK_PREVIEW_TYPE, EekPreviewClass)) + +typedef enum { + PREVIEW_STYLE_ICON = 0, + PREVIEW_STYLE_PREVIEW, + PREVIEW_STYLE_NAME, + PREVIEW_STYLE_BLURB, + PREVIEW_STYLE_ICON_NAME, + PREVIEW_STYLE_ICON_BLURB, + PREVIEW_STYLE_PREVIEW_NAME, + PREVIEW_STYLE_PREVIEW_BLURB +} PreviewStyle; + +typedef enum { + VIEW_TYPE_LIST = 0, + VIEW_TYPE_GRID +} ViewType; + +typedef enum { + PREVIEW_SIZE_TINY = 0, + PREVIEW_SIZE_SMALL, + PREVIEW_SIZE_MEDIUM, + PREVIEW_SIZE_BIG, + PREVIEW_SIZE_BIGGER, + PREVIEW_SIZE_HUGE +} PreviewSize; + +typedef enum { + PREVIEW_LINK_NONE = 0, + PREVIEW_LINK_IN = 1, + PREVIEW_LINK_OUT = 2, + PREVIEW_LINK_OTHER = 4, + PREVIEW_LINK_ALL = 7 +} LinkType; + +typedef struct _EekPreview EekPreview; +typedef struct _EekPreviewClass EekPreviewClass; + + +struct _EekPreview +{ + GtkDrawingArea drawing; + + int _r; + int _g; + int _b; + int _scaledW; + int _scaledH; + + gboolean _hot; + gboolean _within; + gboolean _takesFocus; + + PreviewStyle _prevstyle; + ViewType _view; + PreviewSize _size; + guint _ratio; + guint _linked; + GdkPixbuf* _previewPixbuf; + GdkPixbuf* _scaled; +}; + +struct _EekPreviewClass +{ + GtkDrawingAreaClass parent_class; + + void (*clicked) (EekPreview* splat); +}; + + +GType eek_preview_get_type(void) G_GNUC_CONST; +GtkWidget* eek_preview_new(void); + +void eek_preview_set_details( EekPreview* splat, PreviewStyle prevstyle, ViewType view, PreviewSize size, guint ratio ); +void eek_preview_set_color( EekPreview* splat, int r, int g, int b ); +void eek_preview_set_pixbuf( EekPreview* splat, GdkPixbuf* pixbuf ); + +void eek_preview_set_linked( EekPreview* splat, LinkType link ); +LinkType eek_preview_get_linked( EekPreview* splat ); + +gboolean eek_preview_get_focus_on_click( EekPreview* preview ); +void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click ); + +void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes ); + +G_END_DECLS + +#endif /* SEEN_EEK_PREVIEW_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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp new file mode 100644 index 000000000..5e9d30bcd --- /dev/null +++ b/src/widgets/fill-style.cpp @@ -0,0 +1,552 @@ +/** @file + * @brief Fill style widget + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Frank Felfe <innerspace@iname.com> + * bulia byak <buliabyak@users.sf.net> + * + * Copyright (C) 1999-2005 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#define noSP_FS_VERBOSE + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "desktop-handles.h" +#include "desktop-style.h" +#include "display/sp-canvas.h" +#include "document-private.h" +#include "gradient-chemistry.h" +#include "inkscape.h" +#include "selection.h" +#include "sp-linear-gradient.h" +#include "sp-pattern.h" +#include "sp-radial-gradient.h" +#include "style.h" +#include "widgets/paint-selector.h" +#include "widgets/sp-widget.h" +#include "xml/repr.h" + +#include "widgets/fill-style.h" + + +// These can be deleted once we sort out the libart dependence. + +#define ART_WIND_RULE_NONZERO 0 + +static void sp_fill_style_widget_construct ( SPWidget *spw, + SPPaintSelector *psel ); + +static void sp_fill_style_widget_modify_selection ( SPWidget *spw, + Inkscape::Selection *selection, + guint flags, + SPPaintSelector *psel ); + +static void sp_fill_style_widget_change_subselection ( Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw ); + +static void sp_fill_style_widget_change_selection ( SPWidget *spw, + Inkscape::Selection *selection, + SPPaintSelector *psel ); + +static void sp_fill_style_widget_update (SPWidget *spw); + +static void sp_fill_style_widget_paint_mode_changed ( SPPaintSelector *psel, + SPPaintSelectorMode mode, + SPWidget *spw ); +static void sp_fill_style_widget_fillrule_changed ( SPPaintSelector *psel, + SPPaintSelectorFillRule mode, + SPWidget *spw ); + +static void sp_fill_style_widget_paint_dragged (SPPaintSelector *psel, SPWidget *spw ); +static void sp_fill_style_widget_paint_changed (SPPaintSelector *psel, SPWidget *spw ); + +GtkWidget * +sp_fill_style_widget_new (void) +{ + GtkWidget *spw = sp_widget_new_global (INKSCAPE); + + GtkWidget *vb = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vb); + gtk_container_add (GTK_CONTAINER (spw), vb); + + GtkWidget *psel = sp_paint_selector_new (true); // with fillrule selector + gtk_widget_show (psel); + gtk_box_pack_start (GTK_BOX (vb), psel, TRUE, TRUE, 0); + g_object_set_data (G_OBJECT (spw), "paint-selector", psel); + + g_signal_connect ( G_OBJECT (psel), "mode_changed", + G_CALLBACK (sp_fill_style_widget_paint_mode_changed), + spw ); + + g_signal_connect ( G_OBJECT (psel), "dragged", + G_CALLBACK (sp_fill_style_widget_paint_dragged), + spw ); + + g_signal_connect ( G_OBJECT (psel), "changed", + G_CALLBACK (sp_fill_style_widget_paint_changed), + spw ); + + g_signal_connect ( G_OBJECT (psel), "fillrule_changed", + G_CALLBACK (sp_fill_style_widget_fillrule_changed), + spw ); + + + g_signal_connect ( G_OBJECT (spw), "construct", + G_CALLBACK (sp_fill_style_widget_construct), psel); + +//FIXME: switch these from spw signals to global inkscape object signals; spw just retranslates +//those anyway; then eliminate spw + g_signal_connect ( G_OBJECT (spw), "modify_selection", + G_CALLBACK (sp_fill_style_widget_modify_selection), psel); + + g_signal_connect ( G_OBJECT (spw), "change_selection", + G_CALLBACK (sp_fill_style_widget_change_selection), psel); + + g_signal_connect (INKSCAPE, "change_subselection", G_CALLBACK (sp_fill_style_widget_change_subselection), spw); + + sp_fill_style_widget_update (SP_WIDGET (spw)); + + return spw; + +} // end of sp_fill_style_widget_new() + + + +static void +sp_fill_style_widget_construct( SPWidget *spw, SPPaintSelector */*psel*/ ) +{ +#ifdef SP_FS_VERBOSE + g_print ( "Fill style widget constructed: inkscape %p repr %p\n", + spw->inkscape, spw->repr ); +#endif + if (spw->inkscape) { + sp_fill_style_widget_update (spw); + } + +} // end of sp_fill_style_widget_construct() + +static void +sp_fill_style_widget_modify_selection( SPWidget *spw, + Inkscape::Selection */*selection*/, + guint flags, + SPPaintSelector */*psel*/ ) +{ + if (flags & ( SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_PARENT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG) ) + { + sp_fill_style_widget_update (spw); + } +} + +static void +sp_fill_style_widget_change_subselection( Inkscape::Application */*inkscape*/, + SPDesktop */*desktop*/, + SPWidget *spw ) +{ + sp_fill_style_widget_update (spw); +} + +static void +sp_fill_style_widget_change_selection( SPWidget *spw, + Inkscape::Selection */*selection*/, + SPPaintSelector */*psel*/ ) +{ + sp_fill_style_widget_update (spw); +} + +/** +* \param sel Selection to use, or NULL. +*/ +static void +sp_fill_style_widget_update (SPWidget *spw) +{ + if (g_object_get_data (G_OBJECT (spw), "update")) + return; + + if (g_object_get_data (G_OBJECT (spw), "local")) { + g_object_set_data (G_OBJECT (spw), "local", GINT_TO_POINTER (FALSE)); // local change; do nothing, but reset the flag + return; + } + + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); + + SPPaintSelector *psel = SP_PAINT_SELECTOR (g_object_get_data (G_OBJECT (spw), "paint-selector")); + + // create temporary style + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection + int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FILL); + + switch (result) { + case QUERY_STYLE_NOTHING: + { + /* No paint at all */ + sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_EMPTY); + break; + } + + case QUERY_STYLE_SINGLE: + case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector + case QUERY_STYLE_MULTIPLE_SAME: + { + SPPaintSelectorMode pselmode = sp_style_determine_paint_selector_mode (query, true); + sp_paint_selector_set_mode (psel, pselmode); + + sp_paint_selector_set_fillrule (psel, query->fill_rule.computed == ART_WIND_RULE_NONZERO? + SP_PAINT_SELECTOR_FILLRULE_NONZERO : SP_PAINT_SELECTOR_FILLRULE_EVENODD); + + if (query->fill.set && query->fill.isColor()) { + sp_paint_selector_set_color_alpha (psel, &query->fill.value.color, SP_SCALE24_TO_FLOAT (query->fill_opacity.value)); + } else if (query->fill.set && query->fill.isPaintserver()) { + + SPPaintServer *server = SP_STYLE_FILL_SERVER (query); + + if (SP_IS_LINEARGRADIENT (server)) { + SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); + sp_paint_selector_set_gradient_linear (psel, vector); + + SPLinearGradient *lg = SP_LINEARGRADIENT (server); + sp_paint_selector_set_gradient_properties (psel, + SP_GRADIENT_UNITS (lg), + SP_GRADIENT_SPREAD (lg)); + } else if (SP_IS_RADIALGRADIENT (server)) { + SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); + sp_paint_selector_set_gradient_radial (psel, vector); + + SPRadialGradient *rg = SP_RADIALGRADIENT (server); + sp_paint_selector_set_gradient_properties (psel, + SP_GRADIENT_UNITS (rg), + SP_GRADIENT_SPREAD (rg)); + } else if (SP_IS_PATTERN (server)) { + SPPattern *pat = pattern_getroot (SP_PATTERN (server)); + sp_update_pattern_list (psel, pat); + } + } + break; + } + + case QUERY_STYLE_MULTIPLE_DIFFERENT: + { + sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_MULTIPLE); + break; + } + } + + sp_style_unref(query); + + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); + +} + + +static void +sp_fill_style_widget_paint_mode_changed ( SPPaintSelector *psel, + SPPaintSelectorMode /*mode*/, + SPWidget *spw ) +{ + if (g_object_get_data (G_OBJECT (spw), "update")) + return; + + /* TODO: Does this work? */ + /* TODO: Not really, here we have to get old color back from object */ + /* Instead of relying on paint widget having meaningful colors set */ + sp_fill_style_widget_paint_changed (psel, spw); +} + +static void +sp_fill_style_widget_fillrule_changed ( SPPaintSelector */*psel*/, + SPPaintSelectorFillRule mode, + SPWidget *spw ) +{ + if (g_object_get_data (G_OBJECT (spw), "update")) + return; + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_set_property (css, "fill-rule", mode == SP_PAINT_SELECTOR_FILLRULE_EVENODD? "evenodd":"nonzero"); + + sp_desktop_set_style (desktop, css); + + sp_repr_css_attr_unref (css); + + sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_FILL_STROKE, + _("Change fill rule")); +} + +static gchar const *undo_label_1 = "fill:flatcolor:1"; +static gchar const *undo_label_2 = "fill:flatcolor:2"; +static gchar const *undo_label = undo_label_1; + +/** +This is called repeatedly while you are dragging a color slider, only for flat color +modes. Previously it set the color in style but did not update the repr for efficiency, however +this was flakey and didn't buy us almost anything. So now it does the same as _changed, except +lumps all its changes for undo. + */ +static void +sp_fill_style_widget_paint_dragged (SPPaintSelector *psel, SPWidget *spw) +{ + if (!spw->inkscape) { + return; + } + + if (g_object_get_data (G_OBJECT (spw), "update")) { + return; + } + + if (g_object_get_data (G_OBJECT (spw), "local")) { + // previous local flag not cleared yet; + // this means dragged events come too fast, so we better skip this one to speed up display + // (it's safe to do this in any case) + return; + } + + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); + + switch (psel->mode) { + + case SP_PAINT_SELECTOR_MODE_COLOR_RGB: + case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: + { + sp_paint_selector_set_flat_color (psel, SP_ACTIVE_DESKTOP, "fill", "fill-opacity"); + sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE, + _("Set fill color")); + g_object_set_data (G_OBJECT (spw), "local", GINT_TO_POINTER (TRUE)); // local change, do not update from selection + break; + } + + default: + g_warning ( "file %s: line %d: Paint %d should not emit 'dragged'", + __FILE__, __LINE__, psel->mode ); + break; + + } + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); +} + + +/** +This is called (at least) when: +1 paint selector mode is switched (e.g. flat color -> gradient) +2 you finished dragging a gradient node and released mouse +3 you changed a gradient selector parameter (e.g. spread) +Must update repr. + */ +static void +sp_fill_style_widget_paint_changed ( SPPaintSelector *psel, + SPWidget *spw ) +{ + if (g_object_get_data (G_OBJECT (spw), "update")) { + return; + } + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) { + return; + } + SPDocument *document = sp_desktop_document (desktop); + Inkscape::Selection *selection = sp_desktop_selection (desktop); + + GSList const *items = selection->itemList(); + + switch (psel->mode) { + + case SP_PAINT_SELECTOR_MODE_EMPTY: + // This should not happen. + g_warning ( "file %s: line %d: Paint %d should not emit 'changed'", + __FILE__, __LINE__, psel->mode); + break; + case SP_PAINT_SELECTOR_MODE_MULTIPLE: + // This happens when you switch multiple objects with different gradients to flat color; + // nothing to do here. + break; + + case SP_PAINT_SELECTOR_MODE_NONE: + { + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_set_property (css, "fill", "none"); + + sp_desktop_set_style (desktop, css); + + sp_repr_css_attr_unref (css); + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Remove fill")); + break; + } + + case SP_PAINT_SELECTOR_MODE_COLOR_RGB: + case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: + { + // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in losing release events + sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0); + + sp_paint_selector_set_flat_color (psel, desktop, "fill", "fill-opacity"); + sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE, + _("Set fill color")); + // resume interruptibility + sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop)); + + // on release, toggle undo_label so that the next drag will not be lumped with this one + if (undo_label == undo_label_1) + undo_label = undo_label_2; + else + undo_label = undo_label_1; + + break; + } + + case SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR: + case SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL: + if (items) { + SPGradientType const gradient_type = ( psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR + ? SP_GRADIENT_TYPE_LINEAR + : SP_GRADIENT_TYPE_RADIAL ); + + // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, "fill-opacity", "1.0"); + + SPGradient *vector = sp_paint_selector_get_gradient_vector(psel); + if (!vector) { + /* No vector in paint selector should mean that we just changed mode */ + + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result = objects_query_fillstroke ((GSList *) items, query, true); + guint32 common_rgb = 0; + if (result == QUERY_STYLE_MULTIPLE_SAME) { + if (!query->fill.isColor()) { + common_rgb = sp_desktop_get_color(desktop, true); + } else { + common_rgb = query->fill.value.color.toRGBA32( 0xff ); + } + vector = sp_document_default_gradient_vector(document, common_rgb); + } + sp_style_unref(query); + + for (GSList const *i = items; i != NULL; i = i->next) { + //FIXME: see above + sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style"); + + if (!vector) { + sp_item_set_gradient(SP_ITEM(i->data), + sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), true), + gradient_type, true); + } else { + sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, true); + } + } + } else { + /* We have changed from another gradient type, or modified spread/units within + * this gradient type. */ + vector = sp_gradient_ensure_vector_normalized (vector); + for (GSList const *i = items; i != NULL; i = i->next) { + //FIXME: see above + sp_repr_css_change_recursive (SP_OBJECT_REPR (i->data), css, "style"); + + SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, true); + sp_gradient_selector_attrs_to_gradient (gr, psel); + } + } + + sp_repr_css_attr_unref (css); + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Set gradient on fill")); + } + break; + + case SP_PAINT_SELECTOR_MODE_PATTERN: + + if (items) { + + SPPattern *pattern = sp_paint_selector_get_pattern (psel); + if (!pattern) { + + /* No Pattern in paint selector should mean that we just + * changed mode - dont do jack. + */ + + } else { + Inkscape::XML::Node *patrepr = SP_OBJECT_REPR(pattern); + SPCSSAttr *css = sp_repr_css_attr_new (); + gchar *urltext = g_strdup_printf ("url(#%s)", patrepr->attribute("id")); + sp_repr_css_set_property (css, "fill", urltext); + + // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs + sp_repr_css_set_property(css, "fill-opacity", "1.0"); + + // cannot just call sp_desktop_set_style, because we don't want to touch those + // objects who already have the same root pattern but through a different href + // chain. FIXME: move this to a sp_item_set_pattern + for (GSList const *i = items; i != NULL; i = i->next) { + SPObject *selobj = SP_OBJECT (i->data); + + SPStyle *style = SP_OBJECT_STYLE (selobj); + if (style && style->fill.isPaintserver()) { + SPObject *server = SP_OBJECT_STYLE_FILL_SERVER (selobj); + if (SP_IS_PATTERN (server) && pattern_getroot (SP_PATTERN(server)) == pattern) + // only if this object's pattern is not rooted in our selected pattern, apply + continue; + } + + sp_desktop_apply_css_recursive (selobj, css, true); + } + + sp_repr_css_attr_unref (css); + g_free (urltext); + + } // end if + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Set pattern on fill")); + + } // end if + + break; + + case SP_PAINT_SELECTOR_MODE_UNSET: + if (items) { + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_unset_property (css, "fill"); + + sp_desktop_set_style (desktop, css); + sp_repr_css_attr_unref (css); + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Unset fill")); + } + break; + + default: + g_warning ( "file %s: line %d: Paint selector should not be in " + "mode %d", + __FILE__, __LINE__, psel->mode ); + break; + } + + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/fill-style.h b/src/widgets/fill-style.h new file mode 100644 index 000000000..3924412ec --- /dev/null +++ b/src/widgets/fill-style.h @@ -0,0 +1,33 @@ +/** @file + * @brief Fill style configuration + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * + * Copyright (C) 2002 Lauris Kaplinski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_DIALOGS_SP_FILL_STYLE_H +#define SEEN_DIALOGS_SP_FILL_STYLE_H + +#include <glib.h> +#include <gtk/gtkwidget.h> +#include "forward.h" + + +GtkWidget *sp_fill_style_widget_new (void); + +#endif + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/layer-selector.cpp b/src/widgets/layer-selector.cpp deleted file mode 100644 index d51b31e67..000000000 --- a/src/widgets/layer-selector.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Inkscape::Widgets::LayerSelector - layer selector widget - * - * Authors: - * MenTaLguY <mental@rydia.net> - * - * Copyright (C) 2004 MenTaLguY - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <cstring> -#include <string> -#include <glibmm/i18n.h> - -#include "desktop-handles.h" - -#include "widgets/layer-selector.h" -#include "widgets/shrink-wrap-button.h" -#include "widgets/icon.h" - -#include "util/reverse-list.h" -#include "util/filter-list.h" - -#include "sp-item.h" -#include "desktop.h" -#include "document.h" -#include "dialogs/layer-properties.h" -#include "layer-manager.h" -#include "xml/node-event-vector.h" -#include "verbs.h" - -namespace Inkscape { -namespace Widgets { - -namespace { - -class AlternateIcons : public Gtk::HBox { -public: - AlternateIcons(Inkscape::IconSize size, gchar const *a, gchar const *b) - : _a(NULL), _b(NULL) - { - if (a) { - _a = Gtk::manage(sp_icon_get_icon(a, size)); - _a->set_no_show_all(true); - add(*_a); - } - if (b) { - _b = Gtk::manage(sp_icon_get_icon(b, size)); - _b->set_no_show_all(true); - add(*_b); - } - setState(false); - } - - bool state() const { return _state; } - void setState(bool state) { - _state = state; - if (_state) { - if (_a) { - _a->hide(); - } - if (_b) { - _b->show(); - } - } else { - if (_a) { - _a->show(); - } - if (_b) { - _b->hide(); - } - } - } - -private: - Gtk::Widget *_a; - Gtk::Widget *_b; - bool _state; -}; - -} - -/** LayerSelector constructor. Creates lock and hide buttons, - * initalizes the layer dropdown selector with a label renderer, - * and hooks up signal for setting the desktop layer when the - * selector is changed. - */ -LayerSelector::LayerSelector(SPDesktop *desktop) -: _desktop(NULL), _layer(NULL) -{ - AlternateIcons *label; - - label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "visible", "hidden")); - _visibility_toggle.add(*label); - _visibility_toggle.signal_toggled().connect( - sigc::compose( - sigc::mem_fun(*label, &AlternateIcons::setState), - sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) - ) - ); - _visibility_toggled_connection = _visibility_toggle.signal_toggled().connect( - sigc::compose( - sigc::mem_fun(*this, &LayerSelector::_hideLayer), - sigc::mem_fun(_visibility_toggle, &Gtk::ToggleButton::get_active) - ) - ); - - _visibility_toggle.set_relief(Gtk::RELIEF_NONE); - shrink_wrap_button(_visibility_toggle); - _tooltips.set_tip(_visibility_toggle, _("Toggle current layer visibility")); - pack_start(_visibility_toggle, Gtk::PACK_EXPAND_PADDING); - - label = Gtk::manage(new AlternateIcons(Inkscape::ICON_SIZE_DECORATION, "lock_unlocked", "width_height_lock")); - _lock_toggle.add(*label); - _lock_toggle.signal_toggled().connect( - sigc::compose( - sigc::mem_fun(*label, &AlternateIcons::setState), - sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) - ) - ); - _lock_toggled_connection = _lock_toggle.signal_toggled().connect( - sigc::compose( - sigc::mem_fun(*this, &LayerSelector::_lockLayer), - sigc::mem_fun(_lock_toggle, &Gtk::ToggleButton::get_active) - ) - ); - - _lock_toggle.set_relief(Gtk::RELIEF_NONE); - shrink_wrap_button(_lock_toggle); - _tooltips.set_tip(_lock_toggle, _("Lock or unlock current layer")); - pack_start(_lock_toggle, Gtk::PACK_EXPAND_PADDING); - - _tooltips.set_tip(_selector, _("Current layer")); - pack_start(_selector, Gtk::PACK_EXPAND_WIDGET); - - _layer_model = Gtk::ListStore::create(_model_columns); - _selector.set_model(_layer_model); - _selector.pack_start(_label_renderer); - _selector.set_cell_data_func( - _label_renderer, - sigc::mem_fun(*this, &LayerSelector::_prepareLabelRenderer) - ); - - _selection_changed_connection = _selector.signal_changed().connect( - sigc::mem_fun(*this, &LayerSelector::_setDesktopLayer) - ); - setDesktop(desktop); -} - -/** Destructor - disconnects signal handler - */ -LayerSelector::~LayerSelector() { - setDesktop(NULL); - _selection_changed_connection.disconnect(); -} - -namespace { - -/** Helper function - detaches desktop from selector - */ -bool detach(LayerSelector *selector) { - selector->setDesktop(NULL); - return FALSE; -} - -} - -/** Sets the desktop for the widget. First disconnects signals - * for the current desktop, then stores the pointer to the - * given \a desktop, and attaches its signals to this one. - * Then it selects the current layer for the desktop. - */ -void LayerSelector::setDesktop(SPDesktop *desktop) { - if ( desktop == _desktop ) { - return; - } - - if (_desktop) { -// _desktop_shutdown_connection.disconnect(); - _layer_changed_connection.disconnect(); -// g_signal_handlers_disconnect_by_func(_desktop, (gpointer)&detach, this); - } - _desktop = desktop; - if (_desktop) { - // TODO we need a different signal for this, really..s -// _desktop_shutdown_connection = _desktop->connectShutdown( -// sigc::bind (sigc::ptr_fun (detach), this)); -// g_signal_connect_after(_desktop, "shutdown", GCallback(detach), this); - - _layer_changed_connection = _desktop->connectCurrentLayerChanged( - sigc::mem_fun(*this, &LayerSelector::_selectLayer) - ); - _selectLayer(_desktop->currentLayer()); - } -} - -namespace { - -class is_layer { -public: - is_layer(SPDesktop *desktop) : _desktop(desktop) {} - bool operator()(SPObject &object) const { - return _desktop->isLayer(&object); - } -private: - SPDesktop *_desktop; -}; - -class column_matches_object { -public: - column_matches_object(Gtk::TreeModelColumn<SPObject *> const &column, - SPObject &object) - : _column(column), _object(object) {} - bool operator()(Gtk::TreeModel::const_iterator const &iter) const { - SPObject *current=(*iter)[_column]; - return current == &_object; - } -private: - Gtk::TreeModelColumn<SPObject *> const &_column; - SPObject &_object; -}; - -} - -/** Selects the given layer in the dropdown selector. - */ -void LayerSelector::_selectLayer(SPObject *layer) { - using Inkscape::Util::List; - using Inkscape::Util::cons; - using Inkscape::Util::reverse_list; - - _selection_changed_connection.block(); - - while (!_layer_model->children().empty()) { - Gtk::ListStore::iterator first_row(_layer_model->children().begin()); - _destroyEntry(first_row); - _layer_model->erase(first_row); - } - - SPObject *root=_desktop->currentRoot(); - - if (_layer) { - sp_object_unref(_layer, NULL); - _layer = NULL; - } - - if (layer) { - List<SPObject &> hierarchy=reverse_list<SPObject::ParentIterator>(layer, root); - if ( layer == root ) { - _buildEntries(0, cons(*root, hierarchy)); - } else if (hierarchy) { - _buildSiblingEntries(0, *root, hierarchy); - } - - Gtk::TreeIter row( - std::find_if( - _layer_model->children().begin(), - _layer_model->children().end(), - column_matches_object(_model_columns.object, *layer) - ) - ); - if ( row != _layer_model->children().end() ) { - _selector.set_active(row); - } - - _layer = layer; - sp_object_ref(_layer, NULL); - } - - if ( !layer || layer == root ) { - _visibility_toggle.set_sensitive(false); - _visibility_toggle.set_active(false); - _lock_toggle.set_sensitive(false); - _lock_toggle.set_active(false); - } else { - _visibility_toggle.set_sensitive(true); - _visibility_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false )); - _lock_toggle.set_sensitive(true); - _lock_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false )); - } - - _selection_changed_connection.unblock(); -} - -/** Sets the current desktop layer to the actively selected layer. - */ -void LayerSelector::_setDesktopLayer() { - Gtk::ListStore::iterator selected(_selector.get_active()); - SPObject *layer=_selector.get_active()->get_value(_model_columns.object); - if ( _desktop && layer ) { - _layer_changed_connection.block(); - - _desktop->layer_manager->setCurrentLayer(layer); - - _layer_changed_connection.unblock(); - - _selectLayer(_desktop->currentLayer()); - } - if (_desktop && _desktop->canvas) { - gtk_widget_grab_focus (GTK_WIDGET(_desktop->canvas)); - } -} - -/** Creates rows in the _layer_model data structure for each item - * in \a hierarchy, to a given \a depth. - */ -void LayerSelector::_buildEntries(unsigned depth, - Inkscape::Util::List<SPObject &> hierarchy) -{ - using Inkscape::Util::List; - using Inkscape::Util::rest; - - _buildEntry(depth, *hierarchy); - - List<SPObject &> remainder=rest(hierarchy); - if (remainder) { - _buildEntries(depth+1, remainder); - } else { - _buildSiblingEntries(depth+1, *hierarchy, remainder); - } -} - -/** Creates entries in the _layer_model data structure for - * all siblings of the first child in \a parent. - */ -void LayerSelector::_buildSiblingEntries( - unsigned depth, SPObject &parent, - Inkscape::Util::List<SPObject &> hierarchy -) { - using Inkscape::Util::List; - using Inkscape::Util::rest; - using Inkscape::Util::reverse_list_in_place; - using Inkscape::Util::filter_list; - - Inkscape::Util::List<SPObject &> siblings( - reverse_list_in_place( - filter_list<SPObject::SiblingIterator>( - is_layer(_desktop), parent.firstChild(), NULL - ) - ) - ); - - SPObject *layer( hierarchy ? &*hierarchy : NULL ); - - while (siblings) { - _buildEntry(depth, *siblings); - if ( &*siblings == layer ) { - _buildSiblingEntries(depth+1, *layer, rest(hierarchy)); - } - ++siblings; - } -} - -namespace { - -struct Callbacks { - sigc::slot<void> update_row; - sigc::slot<void> update_list; -}; - -void attribute_changed(Inkscape::XML::Node */*repr*/, gchar const *name, - gchar const */*old_value*/, gchar const */*new_value*/, - bool /*is_interactive*/, void *data) -{ - if ( !std::strcmp(name, "inkscape:groupmode") ) { - reinterpret_cast<Callbacks *>(data)->update_list(); - } else { - reinterpret_cast<Callbacks *>(data)->update_row(); - } -} - -void node_added(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { - gchar const *mode=child->attribute("inkscape:groupmode"); - if ( mode && !std::strcmp(mode, "layer") ) { - reinterpret_cast<Callbacks *>(data)->update_list(); - } -} - -void node_removed(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, Inkscape::XML::Node */*ref*/, void *data) { - gchar const *mode=child->attribute("inkscape:groupmode"); - if ( mode && !std::strcmp(mode, "layer") ) { - reinterpret_cast<Callbacks *>(data)->update_list(); - } -} - -void node_reordered(Inkscape::XML::Node */*parent*/, Inkscape::XML::Node *child, - Inkscape::XML::Node */*old_ref*/, Inkscape::XML::Node */*new_ref*/, - void *data) -{ - gchar const *mode=child->attribute("inkscape:groupmode"); - if ( mode && !std::strcmp(mode, "layer") ) { - reinterpret_cast<Callbacks *>(data)->update_list(); - } -} - -void update_row_for_object(SPObject *object, - Gtk::TreeModelColumn<SPObject *> const &column, - Glib::RefPtr<Gtk::ListStore> const &model) -{ - Gtk::TreeIter row( - std::find_if( - model->children().begin(), - model->children().end(), - column_matches_object(column, *object) - ) - ); - if ( row != model->children().end() ) { - model->row_changed(model->get_path(row), row); - } -} - -void rebuild_all_rows(sigc::slot<void, SPObject *> rebuild, SPDesktop *desktop) -{ - rebuild(desktop->currentLayer()); -} - -} - -void LayerSelector::_protectUpdate(sigc::slot<void> slot) { - bool visibility_blocked=_visibility_toggled_connection.blocked(); - bool lock_blocked=_lock_toggled_connection.blocked(); - _visibility_toggled_connection.block(true); - _lock_toggled_connection.block(true); - slot(); - - SPObject *layer = _desktop ? _desktop->currentLayer() : 0; - if ( layer ) { - bool wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false ); - if ( _lock_toggle.get_active() != wantedValue ) { - _lock_toggle.set_active( wantedValue ); - } - wantedValue = ( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isHidden() : false ); - if ( _visibility_toggle.get_active() != wantedValue ) { - _visibility_toggle.set_active( wantedValue ); - } - } - _visibility_toggled_connection.block(visibility_blocked); - _lock_toggled_connection.block(lock_blocked); -} - -/** Builds and appends a row in the layer model object. - */ -void LayerSelector::_buildEntry(unsigned depth, SPObject &object) { - Inkscape::XML::NodeEventVector *vector; - - Callbacks *callbacks=new Callbacks(); - - callbacks->update_row = sigc::bind( - sigc::mem_fun(*this, &LayerSelector::_protectUpdate), - sigc::bind( - sigc::ptr_fun(&update_row_for_object), - &object, _model_columns.object, _layer_model - ) - ); - - SPObject *layer=_desktop->currentLayer(); - if ( &object == layer || &object == SP_OBJECT_PARENT(layer) ) { - callbacks->update_list = sigc::bind( - sigc::mem_fun(*this, &LayerSelector::_protectUpdate), - sigc::bind( - sigc::ptr_fun(&rebuild_all_rows), - sigc::mem_fun(*this, &LayerSelector::_selectLayer), - _desktop - ) - ); - - Inkscape::XML::NodeEventVector events = { - &node_added, - &node_removed, - &attribute_changed, - NULL, - &node_reordered - }; - - vector = new Inkscape::XML::NodeEventVector(events); - } else { - Inkscape::XML::NodeEventVector events = { - NULL, - NULL, - &attribute_changed, - NULL, - NULL - }; - - vector = new Inkscape::XML::NodeEventVector(events); - } - - Gtk::ListStore::iterator row(_layer_model->append()); - - row->set_value(_model_columns.depth, depth); - - sp_object_ref(&object, NULL); - row->set_value(_model_columns.object, &object); - - Inkscape::GC::anchor(SP_OBJECT_REPR(&object)); - row->set_value(_model_columns.repr, SP_OBJECT_REPR(&object)); - - row->set_value(_model_columns.callbacks, reinterpret_cast<void *>(callbacks)); - - sp_repr_add_listener(SP_OBJECT_REPR(&object), vector, callbacks); -} - -/** Removes a row from the _model_columns object, disconnecting listeners - * on the slot. - */ -void LayerSelector::_destroyEntry(Gtk::ListStore::iterator const &row) { - Callbacks *callbacks=reinterpret_cast<Callbacks *>(row->get_value(_model_columns.callbacks)); - SPObject *object=row->get_value(_model_columns.object); - if (object) { - sp_object_unref(object, NULL); - } - Inkscape::XML::Node *repr=row->get_value(_model_columns.repr); - if (repr) { - sp_repr_remove_listener_by_data(repr, callbacks); - Inkscape::GC::release(repr); - } - delete callbacks; -} - -/** Formats the label for a given layer row - */ -void LayerSelector::_prepareLabelRenderer( - Gtk::TreeModel::const_iterator const &row -) { - unsigned depth=(*row)[_model_columns.depth]; - SPObject *object=(*row)[_model_columns.object]; - bool label_defaulted(false); - - // TODO: when the currently selected row is removed, - // (or before one has been selected) something appears to - // "invent" an iterator with null data and try to render it; - // where does it come from, and how can we avoid it? - if ( object && SP_OBJECT_REPR(object) ) { - SPObject *layer=( _desktop ? _desktop->currentLayer() : NULL ); - SPObject *root=( _desktop ? _desktop->currentRoot() : NULL ); - - bool isancestor = !( (layer && (SP_OBJECT_PARENT(object) == SP_OBJECT_PARENT(layer))) || ((layer == root) && (SP_OBJECT_PARENT(object) == root))); - - bool iscurrent = ( object == layer && object != root ); - - gchar *format = g_strdup_printf ( - "<span size=\"smaller\" %s><tt>%*s%s</tt>%s%s%s%%s%s%s%s</span>", - ( _desktop && _desktop->itemIsHidden (SP_ITEM(object)) ? "foreground=\"gray50\"" : "" ), - depth, "", ( iscurrent ? "•" : " " ), - ( iscurrent ? "<b>" : "" ), - ( SP_ITEM(object)->isLocked() ? "[" : "" ), - ( isancestor ? "<small>" : "" ), - ( isancestor ? "</small>" : "" ), - ( SP_ITEM(object)->isLocked() ? "]" : "" ), - ( iscurrent ? "</b>" : "" ) - ); - - gchar const *label; - if ( object != root ) { - label = object->label(); - if (!label) { - label = object->defaultLabel(); - label_defaulted = true; - } - } else { - label = _("(root)"); - } - - gchar *text = g_markup_printf_escaped(format, label); - _label_renderer.property_markup() = text; - g_free(text); - g_free(format); - } else { - _label_renderer.property_markup() = "<small> </small>"; - } - - _label_renderer.property_ypad() = 1; - _label_renderer.property_style() = ( label_defaulted ? - Pango::STYLE_ITALIC : - Pango::STYLE_NORMAL ); -} - -void LayerSelector::_lockLayer(bool lock) { - if ( _layer && SP_IS_ITEM(_layer) ) { - SP_ITEM(_layer)->setLocked(lock); - sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, - lock? _("Lock layer") : _("Unlock layer")); - } -} - -void LayerSelector::_hideLayer(bool hide) { - if ( _layer && SP_IS_ITEM(_layer) ) { - SP_ITEM(_layer)->setHidden(hide); - sp_document_done(sp_desktop_document(_desktop), SP_VERB_NONE, - hide? _("Hide layer") : _("Unhide layer")); - } -} - -} -} - -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/layer-selector.h b/src/widgets/layer-selector.h deleted file mode 100644 index 0b5300272..000000000 --- a/src/widgets/layer-selector.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Inkscape::Widgets::LayerSelector - layer selector widget - * - * Authors: - * MenTaLguY <mental@rydia.net> - * - * Copyright (C) 2004 MenTaLguY - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifndef SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR -#define SEEN_INKSCAPE_WIDGETS_LAYER_SELECTOR - -#include <gtkmm/box.h> -#include <gtkmm/combobox.h> -#include <gtkmm/togglebutton.h> -#include <gtkmm/tooltips.h> -#include <gtkmm/cellrenderertext.h> -#include <gtkmm/treemodel.h> -#include <gtkmm/liststore.h> -#include <sigc++/slot.h> -#include "util/list.h" - -class SPDesktop; -class SPDocument; -class SPObject; -namespace Inkscape { -namespace XML { -class Node; -} -} - - -namespace Inkscape { -namespace Widgets { - -class DocumentTreeModel; - -class LayerSelector : public Gtk::HBox { -public: - LayerSelector(SPDesktop *desktop = NULL); - ~LayerSelector(); - - SPDesktop *desktop() { return _desktop; } - void setDesktop(SPDesktop *desktop); - -private: - class LayerModelColumns : public Gtk::TreeModel::ColumnRecord { - public: - Gtk::TreeModelColumn<unsigned> depth; - Gtk::TreeModelColumn<SPObject *> object; - Gtk::TreeModelColumn<Inkscape::XML::Node *> repr; - Gtk::TreeModelColumn<void *> callbacks; - - LayerModelColumns() { - add(depth); add(object); add(repr); add(callbacks); - } - }; - - SPDesktop *_desktop; - - Gtk::Tooltips _tooltips; - Gtk::ComboBox _selector; - Gtk::ToggleButton _visibility_toggle; - Gtk::ToggleButton _lock_toggle; - - LayerModelColumns _model_columns; - Gtk::CellRendererText _label_renderer; - Glib::RefPtr<Gtk::ListStore> _layer_model; - -// sigc::connection _desktop_shutdown_connection; - sigc::connection _layer_changed_connection; - sigc::connection _selection_changed_connection; - sigc::connection _visibility_toggled_connection; - sigc::connection _lock_toggled_connection; - - SPObject *_layer; - - void _selectLayer(SPObject *layer); - void _setDesktopLayer(); - - void _buildEntry(unsigned depth, SPObject &object); - void _buildEntries(unsigned depth, - Inkscape::Util::List<SPObject &> hierarchy); - void _buildSiblingEntries(unsigned depth, - SPObject &parent, - Inkscape::Util::List<SPObject &> hierarchy); - void _protectUpdate(sigc::slot<void> slot); - void _destroyEntry(Gtk::ListStore::iterator const &row); - void _hideLayer(bool hide); - void _lockLayer(bool lock); - - void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row); -}; - -} -} - -#endif -/* - 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-attribute-widget.cpp b/src/widgets/sp-attribute-widget.cpp new file mode 100644 index 000000000..de14fc173 --- /dev/null +++ b/src/widgets/sp-attribute-widget.cpp @@ -0,0 +1,790 @@ +/** @file + * @brief Widget that listens and modifies repr attributes + */ +/* Authors: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 2001 Ximian, Inc. + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtk/gtktable.h> +#include <gtk/gtklabel.h> +#include "xml/repr.h" +#include "macros.h" +#include "document.h" +#include "sp-object.h" +#include <glibmm/i18n.h> + +#include <sigc++/functors/ptr_fun.h> +#include <sigc++/adaptors/bind.h> + +#include "sp-attribute-widget.h" + +static void sp_attribute_widget_class_init (SPAttributeWidgetClass *klass); +static void sp_attribute_widget_init (SPAttributeWidget *widget); +static void sp_attribute_widget_destroy (GtkObject *object); + +static void sp_attribute_widget_changed (GtkEditable *editable); + +static void sp_attribute_widget_object_modified ( SPObject *object, + guint flags, + SPAttributeWidget *spaw ); +static void sp_attribute_widget_object_release ( SPObject *object, + SPAttributeWidget *spaw ); + +static GtkEntryClass *parent_class; + + + + +GType sp_attribute_widget_get_type(void) +{ + static GtkType type = 0; + if (!type) { + GTypeInfo info = { + sizeof(SPAttributeWidgetClass), + 0, // base_init + 0, // base_finalize + (GClassInitFunc)sp_attribute_widget_class_init, + 0, // class_finalize + 0, // class_data + sizeof(SPAttributeWidget), + 0, // n_preallocs + (GInstanceInitFunc)sp_attribute_widget_init, + 0 // value_table + }; + type = g_type_register_static(GTK_TYPE_ENTRY, "SPAttributeWidget", &info, static_cast<GTypeFlags>(0)); + } + return type; +} // end of sp_attribute_widget_get_type() + + + +static void +sp_attribute_widget_class_init (SPAttributeWidgetClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkEditableClass *editable_class; + + object_class = GTK_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + editable_class = GTK_EDITABLE_CLASS (klass); + + parent_class = (GtkEntryClass*)gtk_type_class (GTK_TYPE_ENTRY); + + object_class->destroy = sp_attribute_widget_destroy; + + editable_class->changed = sp_attribute_widget_changed; + +} // end of sp_attribute_widget_class_init() + + + +static void +sp_attribute_widget_init (SPAttributeWidget *spaw) +{ + spaw->blocked = FALSE; + spaw->hasobj = FALSE; + + spaw->src.object = NULL; + + spaw->attribute = NULL; + + new (&spaw->modified_connection) sigc::connection(); + new (&spaw->release_connection) sigc::connection(); +} + + + +static void +sp_attribute_widget_destroy (GtkObject *object) +{ + + SPAttributeWidget *spaw; + + spaw = SP_ATTRIBUTE_WIDGET (object); + + if (spaw->attribute) { + g_free (spaw->attribute); + spaw->attribute = NULL; + } + + + if (spaw->hasobj) { + + if (spaw->src.object) { + spaw->modified_connection.disconnect(); + spaw->release_connection.disconnect(); + spaw->src.object = NULL; + } + } else { + + if (spaw->src.repr) { + spaw->src.repr = Inkscape::GC::release(spaw->src.repr); + } + } // end of if() + + spaw->modified_connection.~connection(); + spaw->release_connection.~connection(); + + ((GtkObjectClass *) parent_class)->destroy (object); + +} + + + +static void +sp_attribute_widget_changed (GtkEditable *editable) +{ + + SPAttributeWidget *spaw; + + spaw = SP_ATTRIBUTE_WIDGET (editable); + + if (!spaw->blocked) { + + const gchar *text; + spaw->blocked = TRUE; + text = gtk_entry_get_text (GTK_ENTRY (spaw)); + if (!*text) + text = NULL; + + if (spaw->hasobj && spaw->src.object) { + + SP_OBJECT_REPR (spaw->src.object)->setAttribute(spaw->attribute, text, false); + sp_document_done (SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE, + _("Set attribute")); + + } else if (spaw->src.repr) { + + spaw->src.repr->setAttribute(spaw->attribute, text, false); + /* TODO: Warning! Undo will not be flushed in given case */ + } + spaw->blocked = FALSE; + } + +} // end of sp_attribute_widget_changed() + + + +GtkWidget * +sp_attribute_widget_new ( SPObject *object, const gchar *attribute ) +{ + SPAttributeWidget *spaw; + + g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL); + g_return_val_if_fail (!object || attribute, NULL); + + spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET); + + sp_attribute_widget_set_object (spaw, object, attribute); + + return GTK_WIDGET (spaw); + +} // end of sp_attribute_widget_new() + + + +GtkWidget * +sp_attribute_widget_new_repr ( Inkscape::XML::Node *repr, const gchar *attribute ) +{ + SPAttributeWidget *spaw; + + spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET); + + sp_attribute_widget_set_repr (spaw, repr, attribute); + + return GTK_WIDGET (spaw); +} + + + +void +sp_attribute_widget_set_object ( SPAttributeWidget *spaw, + SPObject *object, + const gchar *attribute ) +{ + + g_return_if_fail (spaw != NULL); + g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw)); + g_return_if_fail (!object || SP_IS_OBJECT (object)); + g_return_if_fail (!object || attribute); + g_return_if_fail (attribute != NULL); + + if (spaw->attribute) { + g_free (spaw->attribute); + spaw->attribute = NULL; + } + + if (spaw->hasobj) { + + if (spaw->src.object) { + spaw->modified_connection.disconnect(); + spaw->release_connection.disconnect(); + spaw->src.object = NULL; + } + } else { + + if (spaw->src.repr) { + spaw->src.repr = Inkscape::GC::release(spaw->src.repr); + } + } + + spaw->hasobj = TRUE; + + if (object) { + const gchar *val; + + spaw->blocked = TRUE; + spaw->src.object = object; + + spaw->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_widget_object_modified), spaw)); + spaw->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_widget_object_release), spaw)); + + spaw->attribute = g_strdup (attribute); + + val = SP_OBJECT_REPR (object)->attribute(attribute); + gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) ""); + spaw->blocked = FALSE; + } + + gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.object != NULL)); + +} // end of sp_attribute_widget_set_object() + + + +void +sp_attribute_widget_set_repr ( SPAttributeWidget *spaw, + Inkscape::XML::Node *repr, + const gchar *attribute ) +{ + + g_return_if_fail (spaw != NULL); + g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw)); + g_return_if_fail (attribute != NULL); + + if (spaw->attribute) { + g_free (spaw->attribute); + spaw->attribute = NULL; + } + + if (spaw->hasobj) { + + if (spaw->src.object) { + spaw->modified_connection.disconnect(); + spaw->release_connection.disconnect(); + spaw->src.object = NULL; + } + } else { + + if (spaw->src.repr) { + spaw->src.repr = Inkscape::GC::release(spaw->src.repr); + } + } + + spaw->hasobj = FALSE; + + if (repr) { + const gchar *val; + + spaw->blocked = TRUE; + spaw->src.repr = Inkscape::GC::anchor(repr); + spaw->attribute = g_strdup (attribute); + + val = repr->attribute(attribute); + gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) ""); + spaw->blocked = FALSE; + } + + gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.repr != NULL)); + +} // end of sp_attribute_widget_set_repr() + + + +static void +sp_attribute_widget_object_modified ( SPObject */*object*/, + guint flags, + SPAttributeWidget *spaw ) +{ + + if (flags && SP_OBJECT_MODIFIED_FLAG) { + + const gchar *val, *text; + val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute); + text = gtk_entry_get_text (GTK_ENTRY (spaw)); + + if (val || text) { + + if (!val || !text || strcmp (val, text)) { + /* We are different */ + spaw->blocked = TRUE; + gtk_entry_set_text ( GTK_ENTRY (spaw), + val ? val : (const gchar *) ""); + spaw->blocked = FALSE; + } // end of if() + + } // end of if() + + } //end of if() + +} // end of sp_attribute_widget_object_modified() + + + +static void +sp_attribute_widget_object_release ( SPObject */*object*/, + SPAttributeWidget *spaw ) +{ + sp_attribute_widget_set_object (spaw, NULL, NULL); +} + + + +/* SPAttributeTable */ + +static void sp_attribute_table_class_init (SPAttributeTableClass *klass); +static void sp_attribute_table_init (SPAttributeTable *widget); +static void sp_attribute_table_destroy (GtkObject *object); + +static void sp_attribute_table_object_modified (SPObject *object, guint flags, SPAttributeTable *spaw); +static void sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spaw); +static void sp_attribute_table_entry_changed (GtkEditable *editable, SPAttributeTable *spat); + +static GtkVBoxClass *table_parent_class; + + + + +GType sp_attribute_table_get_type(void) +{ + static GtkType type = 0; + if (!type) { + GTypeInfo info = { + sizeof(SPAttributeTableClass), + 0, // base_init + 0, // base_finalize + (GClassInitFunc)sp_attribute_table_class_init, + 0, // class_finalize + 0, // class_data + sizeof(SPAttributeTable), + 0, // n_preallocs + (GInstanceInitFunc)sp_attribute_table_init, + 0 // value_table + }; + type = g_type_register_static(GTK_TYPE_VBOX, "SPAttributeTable", &info, static_cast<GTypeFlags>(0)); + } + return type; +} // end of sp_attribute_table_get_type() + + + +static void +sp_attribute_table_class_init (SPAttributeTableClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = GTK_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX); + + object_class->destroy = sp_attribute_table_destroy; + +} // end of sp_attribute_table_class_init() + + + +static void +sp_attribute_table_init ( SPAttributeTable *spat ) +{ + spat->blocked = FALSE; + spat->hasobj = FALSE; + spat->table = NULL; + spat->src.object = NULL; + spat->num_attr = 0; + spat->attributes = NULL; + spat->entries = NULL; + + new (&spat->modified_connection) sigc::connection(); + new (&spat->release_connection) sigc::connection(); +} + +static void +sp_attribute_table_destroy ( GtkObject *object ) +{ + SPAttributeTable *spat; + + spat = SP_ATTRIBUTE_TABLE (object); + + if (spat->attributes) { + gint i; + for (i = 0; i < spat->num_attr; i++) { + g_free (spat->attributes[i]); + } + g_free (spat->attributes); + spat->attributes = NULL; + } + + if (spat->hasobj) { + + if (spat->src.object) { + spat->modified_connection.disconnect(); + spat->release_connection.disconnect(); + spat->src.object = NULL; + } + } else { + if (spat->src.repr) { + spat->src.repr = Inkscape::GC::release(spat->src.repr); + } + } // end of if() + + spat->modified_connection.~connection(); + spat->release_connection.~connection(); + + if (spat->entries) { + g_free (spat->entries); + spat->entries = NULL; + } + + spat->table = NULL; + + if (((GtkObjectClass *) table_parent_class)->destroy) { + (* ((GtkObjectClass *) table_parent_class)->destroy) (object); + } + +} // end of sp_attribute_table_destroy() + + +GtkWidget * +sp_attribute_table_new ( SPObject *object, + gint num_attr, + const gchar **labels, + const gchar **attributes ) +{ + SPAttributeTable *spat; + + g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL); + g_return_val_if_fail (!object || (num_attr > 0), NULL); + g_return_val_if_fail (!num_attr || (labels && attributes), NULL); + + spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE); + + sp_attribute_table_set_object (spat, object, num_attr, labels, attributes); + + return GTK_WIDGET (spat); + +} // end of sp_attribute_table_new() + + + +GtkWidget * +sp_attribute_table_new_repr ( Inkscape::XML::Node *repr, + gint num_attr, + const gchar **labels, + const gchar **attributes ) +{ + SPAttributeTable *spat; + + g_return_val_if_fail (!num_attr || (labels && attributes), NULL); + + spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE); + + sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes); + + return GTK_WIDGET (spat); + +} // end of sp_attribute_table_new_repr() + + + +#define XPAD 4 +#define YPAD 0 + +void +sp_attribute_table_set_object ( SPAttributeTable *spat, + SPObject *object, + gint num_attr, + const gchar **labels, + const gchar **attributes ) +{ + + g_return_if_fail (spat != NULL); + g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat)); + g_return_if_fail (!object || SP_IS_OBJECT (object)); + g_return_if_fail (!object || (num_attr > 0)); + g_return_if_fail (!num_attr || (labels && attributes)); + + if (spat->table) { + gtk_widget_destroy (spat->table); + spat->table = NULL; + } + + if (spat->attributes) { + gint i; + for (i = 0; i < spat->num_attr; i++) { + g_free (spat->attributes[i]); + } + g_free (spat->attributes); + spat->attributes = NULL; + } + + if (spat->entries) { + g_free (spat->entries); + spat->entries = NULL; + } + + if (spat->hasobj) { + if (spat->src.object) { + spat->modified_connection.disconnect(); + spat->release_connection.disconnect(); + spat->src.object = NULL; + } + } else { + if (spat->src.repr) { + spat->src.repr = Inkscape::GC::release(spat->src.repr); + } + } + + spat->hasobj = TRUE; + + if (object) { + gint i; + + spat->blocked = TRUE; + + /* Set up object */ + spat->src.object = object; + spat->num_attr = num_attr; + + spat->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_table_object_modified), spat)); + spat->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_table_object_release), spat)); + + /* Create table */ + spat->table = gtk_table_new (num_attr, 2, FALSE); + gtk_container_add (GTK_CONTAINER (spat), spat->table); + /* Arrays */ + spat->attributes = g_new0 (gchar *, num_attr); + spat->entries = g_new0 (GtkWidget *, num_attr); + /* Fill rows */ + for (i = 0; i < num_attr; i++) { + GtkWidget *w; + const gchar *val; + + spat->attributes[i] = g_strdup (attributes[i]); + w = gtk_label_new (_(labels[i])); + gtk_widget_show (w); + gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1, + GTK_FILL, + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + XPAD, YPAD ); + w = gtk_entry_new (); + gtk_widget_show (w); + val = SP_OBJECT_REPR (object)->attribute(attributes[i]); + gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) ""); + gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1, + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + XPAD, YPAD ); + spat->entries[i] = w; + g_signal_connect ( G_OBJECT (w), "changed", + G_CALLBACK (sp_attribute_table_entry_changed), + spat ); + } + /* Show table */ + gtk_widget_show (spat->table); + + spat->blocked = FALSE; + } + + gtk_widget_set_sensitive ( GTK_WIDGET (spat), + (spat->src.object != NULL) ); + +} // end of sp_attribute_table_set_object() + + + +void +sp_attribute_table_set_repr ( SPAttributeTable *spat, + Inkscape::XML::Node *repr, + gint num_attr, + const gchar **labels, + const gchar **attributes ) +{ + g_return_if_fail (spat != NULL); + g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat)); + g_return_if_fail (!num_attr || (labels && attributes)); + + if (spat->table) { + gtk_widget_destroy (spat->table); + spat->table = NULL; + } + + if (spat->attributes) { + gint i; + for (i = 0; i < spat->num_attr; i++) { + g_free (spat->attributes[i]); + } + g_free (spat->attributes); + spat->attributes = NULL; + } + + if (spat->entries) { + g_free (spat->entries); + spat->entries = NULL; + } + + if (spat->hasobj) { + if (spat->src.object) { + spat->modified_connection.disconnect(); + spat->release_connection.disconnect(); + spat->src.object = NULL; + } + } else { + if (spat->src.repr) { + spat->src.repr = Inkscape::GC::release(spat->src.repr); + } + } + + spat->hasobj = FALSE; + + if (repr) { + gint i; + + spat->blocked = TRUE; + + /* Set up repr */ + spat->src.repr = Inkscape::GC::anchor(repr); + spat->num_attr = num_attr; + /* Create table */ + spat->table = gtk_table_new (num_attr, 2, FALSE); + gtk_container_add (GTK_CONTAINER (spat), spat->table); + /* Arrays */ + spat->attributes = g_new0 (gchar *, num_attr); + spat->entries = g_new0 (GtkWidget *, num_attr); + + /* Fill rows */ + for (i = 0; i < num_attr; i++) { + GtkWidget *w; + const gchar *val; + + spat->attributes[i] = g_strdup (attributes[i]); + w = gtk_label_new (labels[i]); + gtk_widget_show (w); + gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1, + GTK_FILL, + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + XPAD, YPAD ); + w = gtk_entry_new (); + gtk_widget_show (w); + val = repr->attribute(attributes[i]); + gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) ""); + gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1, + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + XPAD, YPAD ); + spat->entries[i] = w; + g_signal_connect ( G_OBJECT (w), "changed", + G_CALLBACK (sp_attribute_table_entry_changed), + spat ); + } + /* Show table */ + gtk_widget_show (spat->table); + + spat->blocked = FALSE; + } + + gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL)); + +} // end of sp_attribute_table_set_repr() + + + +static void +sp_attribute_table_object_modified ( SPObject */*object*/, + guint flags, + SPAttributeTable *spat ) +{ + if (flags && SP_OBJECT_MODIFIED_FLAG) + { + gint i; + for (i = 0; i < spat->num_attr; i++) { + const gchar *val, *text; + val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]); + text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i])); + if (val || text) { + if (!val || !text || strcmp (val, text)) { + /* We are different */ + spat->blocked = TRUE; + gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]), + val ? val : (const gchar *) ""); + spat->blocked = FALSE; + } + } + } + } // end of if() + +} // end of sp_attribute_table_object_modified() + + + +static void +sp_attribute_table_object_release (SPObject */*object*/, SPAttributeTable *spat) +{ + sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL); +} + + + +static void +sp_attribute_table_entry_changed ( GtkEditable *editable, + SPAttributeTable *spat ) +{ + if (!spat->blocked) + { + gint i; + for (i = 0; i < spat->num_attr; i++) { + + if (GTK_WIDGET (editable) == spat->entries[i]) { + const gchar *text; + spat->blocked = TRUE; + text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i])); + + if (!*text) + text = NULL; + + if (spat->hasobj && spat->src.object) { + SP_OBJECT_REPR (spat->src.object)->setAttribute(spat->attributes[i], text, false); + sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE, + _("Set attribute")); + + } else if (spat->src.repr) { + + spat->src.repr->setAttribute(spat->attributes[i], text, false); + /* TODO: Warning! Undo will not be flushed in given case */ + } + spat->blocked = FALSE; + return; + } + } + g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__); + } // end of if() + +} // end of sp_attribute_table_entry_changed() + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-attribute-widget.h b/src/widgets/sp-attribute-widget.h new file mode 100644 index 000000000..01da29bed --- /dev/null +++ b/src/widgets/sp-attribute-widget.h @@ -0,0 +1,130 @@ +/** @file + * @brief Widget that listens and modifies repr attributes + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * + * Copyright (C) 2002 authors + * Copyright (C) 2001 Ximian, Inc. + * + * Licensed under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H +#define SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H + +#include <glib.h> +#include <sigc++/connection.h> + +#define SP_TYPE_ATTRIBUTE_WIDGET (sp_attribute_widget_get_type ()) +#define SP_ATTRIBUTE_WIDGET(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_ATTRIBUTE_WIDGET, SPAttributeWidget)) +#define SP_ATTRIBUTE_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_ATTRIBUTE_WIDGET, SPAttributeWidgetClass)) +#define SP_IS_ATTRIBUTE_WIDGET(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_ATTRIBUTE_WIDGET)) +#define SP_IS_ATTRIBUTE_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_ATTRIBUTE_WIDGET)) + +#define SP_TYPE_ATTRIBUTE_TABLE (sp_attribute_table_get_type ()) +#define SP_ATTRIBUTE_TABLE(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_ATTRIBUTE_TABLE, SPAttributeTable)) +#define SP_ATTRIBUTE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_ATTRIBUTE_TABLE, SPAttributeTableClass)) +#define SP_IS_ATTRIBUTE_TABLE(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_ATTRIBUTE_TABLE)) +#define SP_IS_ATTRIBUTE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_ATTRIBUTE_TABLE)) + +namespace Inkscape { +namespace XML { +class Node; +} +} + + +struct SPAttributeWidget; +struct SPAttributeWidgetClass; + +struct SPAttributeTable; +struct SPAttributeTableClass; + +#include <gtk/gtkentry.h> +#include <gtk/gtkvbox.h> + +#include <forward.h> + +struct SPAttributeWidget { + GtkEntry entry; + guint blocked : 1; + guint hasobj : 1; + union { + SPObject *object; + Inkscape::XML::Node *repr; + } src; + gchar *attribute; + + sigc::connection modified_connection; + sigc::connection release_connection; +}; + +struct SPAttributeWidgetClass { + GtkEntryClass entry_class; +}; + +GtkType sp_attribute_widget_get_type (void); + +GtkWidget *sp_attribute_widget_new (SPObject *object, const gchar *attribute); +GtkWidget *sp_attribute_widget_new_repr (Inkscape::XML::Node *repr, const gchar *attribute); + +void sp_attribute_widget_set_object ( SPAttributeWidget *spw, + SPObject *object, + const gchar *attribute ); +void sp_attribute_widget_set_repr ( SPAttributeWidget *spw, + Inkscape::XML::Node *repr, + const gchar *attribute ); + +/* SPAttributeTable */ + +struct SPAttributeTable { + GtkVBox vbox; + guint blocked : 1; + guint hasobj : 1; + GtkWidget *table; + union { + SPObject *object; + Inkscape::XML::Node *repr; + } src; + gint num_attr; + gchar **attributes; + GtkWidget **entries; + + sigc::connection modified_connection; + sigc::connection release_connection; +}; + +struct SPAttributeTableClass { + GtkEntryClass entry_class; +}; + +GtkType sp_attribute_table_get_type (void); + +GtkWidget *sp_attribute_table_new ( SPObject *object, gint num_attr, + const gchar **labels, + const gchar **attributes ); +GtkWidget *sp_attribute_table_new_repr ( Inkscape::XML::Node *repr, gint num_attr, + const gchar **labels, + const gchar **attributes ); +void sp_attribute_table_set_object ( SPAttributeTable *spw, + SPObject *object, gint num_attr, + const gchar **labels, + const gchar **attrs ); +void sp_attribute_table_set_repr ( SPAttributeTable *spw, + Inkscape::XML::Node *repr, gint num_attr, + const gchar **labels, + const gchar **attrs ); + +#endif + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp new file mode 100644 index 000000000..b1678f266 --- /dev/null +++ b/src/widgets/stroke-style.cpp @@ -0,0 +1,1838 @@ +/** @file + * @brief Stroke style dialog + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Bryce Harrington <brycehar@bryceharrington.org> + * bulia byak <buliabyak@users.sf.net> + * Maximilian Albert <maximilian.albert@gmail.com> + * Josh Andler <scislac@users.sf.net> + * + * Copyright (C) 2001-2005 authors + * Copyright (C) 2001 Ximian, Inc. + * Copyright (C) 2004 John Cliff + * Copyright (C) 2008 Maximilian Albert (gtkmm-ification) + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#define noSP_SS_VERBOSE + +#include <glib/gmem.h> +#include <gtk/gtk.h> +#include <glibmm/i18n.h> + +#include "desktop-handles.h" +#include "desktop-style.h" +#include "dialogs/dialog-events.h" +#include "display/nr-arena.h" +#include "display/nr-arena-item.h" +#include "document-private.h" +#include "gradient-chemistry.h" +#include "helper/stock-items.h" +#include "helper/unit-menu.h" +#include "helper/units.h" +#include "inkscape.h" +#include "io/sys.h" +#include "marker.h" +#include "path-prefix.h" +#include "selection.h" +#include "sp-linear-gradient.h" +#include "sp-namedview.h" +#include "sp-pattern.h" +#include "sp-radial-gradient.h" +#include "sp-rect.h" +#include "sp-text.h" +#include "style.h" +#include "svg/css-ostringstream.h" +#include "ui/cache/svg_preview_cache.h" +#include "ui/icon-names.h" +#include "widgets/dash-selector.h" +#include "widgets/icon.h" +#include "widgets/paint-selector.h" +#include "widgets/sp-widget.h" +#include "widgets/spw-utilities.h" +#include "xml/repr.h" + +#include "widgets/stroke-style.h" + + +/* Paint */ + +static void sp_stroke_style_paint_selection_modified (SPWidget *spw, Inkscape::Selection *selection, guint flags, SPPaintSelector *psel); +static void sp_stroke_style_paint_selection_changed (SPWidget *spw, Inkscape::Selection *selection, SPPaintSelector *psel); +static void sp_stroke_style_paint_update(SPWidget *spw); + +static void sp_stroke_style_paint_mode_changed(SPPaintSelector *psel, SPPaintSelectorMode mode, SPWidget *spw); +static void sp_stroke_style_paint_dragged(SPPaintSelector *psel, SPWidget *spw); +static void sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw); + +static void sp_stroke_style_widget_change_subselection ( Inkscape::Application *inkscape, SPDesktop *desktop, SPWidget *spw ); +static void sp_stroke_style_widget_transientize_callback(Inkscape::Application *inkscape, + SPDesktop *desktop, + SPWidget *spw ); + +/** 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 SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); +static void ink_markers_menu_update(Gtk::Container* spw, SPMarkerLoc const which); + +static Inkscape::UI::Cache::SvgPreview svg_preview_cache; + +/** + * Create the stroke style widget, and hook up all the signals. + */ +GtkWidget * +sp_stroke_style_paint_widget_new(void) +{ + GtkWidget *spw, *psel; + + spw = sp_widget_new_global(INKSCAPE); + + psel = sp_paint_selector_new(false); // without fillrule selector + gtk_widget_show(psel); + gtk_container_add(GTK_CONTAINER(spw), psel); + gtk_object_set_data(GTK_OBJECT(spw), "paint-selector", psel); + + gtk_signal_connect(GTK_OBJECT(spw), "modify_selection", + GTK_SIGNAL_FUNC(sp_stroke_style_paint_selection_modified), + psel); + gtk_signal_connect(GTK_OBJECT(spw), "change_selection", + GTK_SIGNAL_FUNC(sp_stroke_style_paint_selection_changed), + psel); + + g_signal_connect (INKSCAPE, "change_subselection", G_CALLBACK (sp_stroke_style_widget_change_subselection), spw); + + g_signal_connect (G_OBJECT(INKSCAPE), "activate_desktop", G_CALLBACK (sp_stroke_style_widget_transientize_callback), spw ); + + gtk_signal_connect(GTK_OBJECT(psel), "mode_changed", + GTK_SIGNAL_FUNC(sp_stroke_style_paint_mode_changed), + spw); + gtk_signal_connect(GTK_OBJECT(psel), "dragged", + GTK_SIGNAL_FUNC(sp_stroke_style_paint_dragged), + spw); + gtk_signal_connect(GTK_OBJECT(psel), "changed", + GTK_SIGNAL_FUNC(sp_stroke_style_paint_changed), + spw); + + sp_stroke_style_paint_update (SP_WIDGET(spw)); + return spw; +} + +/** + * On signal modified, invokes an update of the stroke style paint object. + */ +static void +sp_stroke_style_paint_selection_modified( SPWidget *spw, + Inkscape::Selection */*selection*/, + guint flags, + SPPaintSelector */*psel*/ ) +{ + if (flags & ( SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG) ) { + sp_stroke_style_paint_update(spw); + } +} + + +/** + * On signal selection changed, invokes an update of the stroke style paint object. + */ +static void +sp_stroke_style_paint_selection_changed( SPWidget *spw, + Inkscape::Selection */*selection*/, + SPPaintSelector */*psel*/ ) +{ + sp_stroke_style_paint_update (spw); +} + + +/** + * On signal change subselection, invoke an update of the stroke style widget. + */ +static void +sp_stroke_style_widget_change_subselection( Inkscape::Application */*inkscape*/, + SPDesktop */*desktop*/, + SPWidget *spw ) +{ + sp_stroke_style_paint_update (spw); +} + +/** + * Gets the active stroke style property, then sets the appropriate color, alpha, gradient, + * pattern, etc. for the paint-selector. + */ +static void +sp_stroke_style_paint_update (SPWidget *spw) +{ + if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { + return; + } + + gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(TRUE)); + + SPPaintSelector *psel = SP_PAINT_SELECTOR(gtk_object_get_data(GTK_OBJECT(spw), "paint-selector")); + + // create temporary style + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + // query into it + int result = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKE); + + switch (result) { + case QUERY_STYLE_NOTHING: + { + /* No paint at all */ + sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_EMPTY); + break; + } + + case QUERY_STYLE_SINGLE: + case QUERY_STYLE_MULTIPLE_AVERAGED: // TODO: treat this slightly differently, e.g. display "averaged" somewhere in paint selector + case QUERY_STYLE_MULTIPLE_SAME: + { + SPPaintSelectorMode pselmode = sp_style_determine_paint_selector_mode (query, false); + sp_paint_selector_set_mode (psel, pselmode); + + if (query->stroke.set && query->stroke.isPaintserver()) { + + SPPaintServer *server = SP_STYLE_STROKE_SERVER (query); + + if (SP_IS_LINEARGRADIENT (server)) { + SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); + sp_paint_selector_set_gradient_linear (psel, vector); + + SPLinearGradient *lg = SP_LINEARGRADIENT (server); + sp_paint_selector_set_gradient_properties (psel, + SP_GRADIENT_UNITS (lg), + SP_GRADIENT_SPREAD (lg)); + } else if (SP_IS_RADIALGRADIENT (server)) { + SPGradient *vector = sp_gradient_get_vector (SP_GRADIENT (server), FALSE); + sp_paint_selector_set_gradient_radial (psel, vector); + + SPRadialGradient *rg = SP_RADIALGRADIENT (server); + sp_paint_selector_set_gradient_properties (psel, + SP_GRADIENT_UNITS (rg), + SP_GRADIENT_SPREAD (rg)); + } else if (SP_IS_PATTERN (server)) { + SPPattern *pat = pattern_getroot (SP_PATTERN (server)); + sp_update_pattern_list (psel, pat); + } + } else if (query->stroke.set && query->stroke.isColor()) { + sp_paint_selector_set_color_alpha (psel, &query->stroke.value.color, SP_SCALE24_TO_FLOAT (query->stroke_opacity.value)); + + } + break; + } + + case QUERY_STYLE_MULTIPLE_DIFFERENT: + { + sp_paint_selector_set_mode (psel, SP_PAINT_SELECTOR_MODE_MULTIPLE); + break; + } + } + + sp_style_unref(query); + + gtk_object_set_data(GTK_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); +} + +/** + * When the mode is changed, invoke a regular changed handler. + */ +static void +sp_stroke_style_paint_mode_changed( SPPaintSelector *psel, + SPPaintSelectorMode /*mode*/, + SPWidget *spw ) +{ + if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { + return; + } + + /* TODO: Does this work? + * Not really, here we have to get old color back from object + * Instead of relying on paint widget having meaningful colors set + */ + sp_stroke_style_paint_changed(psel, spw); +} + +static gchar const *const undo_label_1 = "stroke:flatcolor:1"; +static gchar const *const undo_label_2 = "stroke:flatcolor:2"; +static gchar const *undo_label = undo_label_1; + +/** + * When a drag callback occurs on a paint selector object, if it is a RGB or CMYK + * color mode, then set the stroke opacity to psel's flat color. + */ +static void +sp_stroke_style_paint_dragged(SPPaintSelector *psel, SPWidget *spw) +{ + if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { + return; + } + + switch (psel->mode) { + case SP_PAINT_SELECTOR_MODE_COLOR_RGB: + case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: + { + sp_paint_selector_set_flat_color (psel, SP_ACTIVE_DESKTOP, "stroke", "stroke-opacity"); + sp_document_maybe_done (sp_desktop_document(SP_ACTIVE_DESKTOP), undo_label, SP_VERB_DIALOG_FILL_STROKE, + _("Set stroke color")); + break; + } + + default: + g_warning( "file %s: line %d: Paint %d should not emit 'dragged'", + __FILE__, __LINE__, psel->mode); + break; + } +} + +/** + * When the stroke style's paint settings change, this handler updates the + * repr's stroke css style and applies the style to relevant drawing items. + */ +static void +sp_stroke_style_paint_changed(SPPaintSelector *psel, SPWidget *spw) +{ + if (gtk_object_get_data(GTK_OBJECT(spw), "update")) { + return; + } + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (TRUE)); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *document = sp_desktop_document (desktop); + Inkscape::Selection *selection = sp_desktop_selection (desktop); + + GSList const *items = selection->itemList(); + + switch (psel->mode) { + case SP_PAINT_SELECTOR_MODE_EMPTY: + // This should not happen. + g_warning ( "file %s: line %d: Paint %d should not emit 'changed'", + __FILE__, __LINE__, psel->mode); + break; + case SP_PAINT_SELECTOR_MODE_MULTIPLE: + // This happens when you switch multiple objects with different gradients to flat color; + // nothing to do here. + break; + + case SP_PAINT_SELECTOR_MODE_NONE: + { + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, "stroke", "none"); + + sp_desktop_set_style (desktop, css); + + sp_repr_css_attr_unref(css); + + sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, + _("Remove stroke")); + break; + } + + case SP_PAINT_SELECTOR_MODE_COLOR_RGB: + case SP_PAINT_SELECTOR_MODE_COLOR_CMYK: + { + sp_paint_selector_set_flat_color (psel, desktop, "stroke", "stroke-opacity"); + sp_document_maybe_done (sp_desktop_document(desktop), undo_label, SP_VERB_DIALOG_FILL_STROKE, + _("Set stroke color")); + + // on release, toggle undo_label so that the next drag will not be lumped with this one + if (undo_label == undo_label_1) + undo_label = undo_label_2; + else + undo_label = undo_label_1; + + break; + } + + case SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR: + case SP_PAINT_SELECTOR_MODE_GRADIENT_RADIAL: + if (items) { + SPGradientType const gradient_type = ( psel->mode == SP_PAINT_SELECTOR_MODE_GRADIENT_LINEAR + ? SP_GRADIENT_TYPE_LINEAR + : SP_GRADIENT_TYPE_RADIAL ); + SPGradient *vector = sp_paint_selector_get_gradient_vector(psel); + if (!vector) { + /* No vector in paint selector should mean that we just changed mode */ + + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result = objects_query_fillstroke ((GSList *) items, query, false); + guint32 common_rgb = 0; + if (result == QUERY_STYLE_MULTIPLE_SAME) { + if (!query->fill.isColor()) { + common_rgb = sp_desktop_get_color(desktop, false); + } else { + common_rgb = query->stroke.value.color.toRGBA32( 0xff ); + } + vector = sp_document_default_gradient_vector(document, common_rgb); + } + sp_style_unref(query); + + for (GSList const *i = items; i != NULL; i = i->next) { + if (!vector) { + sp_item_set_gradient(SP_ITEM(i->data), + sp_gradient_vector_for_object(document, desktop, SP_OBJECT(i->data), false), + gradient_type, false); + } else { + sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, false); + } + } + } else { + vector = sp_gradient_ensure_vector_normalized(vector); + for (GSList const *i = items; i != NULL; i = i->next) { + SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, false); + sp_gradient_selector_attrs_to_gradient(gr, psel); + } + } + + sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, + _("Set gradient on stroke")); + } + break; + + case SP_PAINT_SELECTOR_MODE_PATTERN: + + if (items) { + + SPPattern *pattern = sp_paint_selector_get_pattern (psel); + if (!pattern) { + + /* No Pattern in paint selector should mean that we just + * changed mode - dont do jack. + */ + + } else { + Inkscape::XML::Node *patrepr = SP_OBJECT_REPR(pattern); + SPCSSAttr *css = sp_repr_css_attr_new (); + gchar *urltext = g_strdup_printf ("url(#%s)", patrepr->attribute("id")); + sp_repr_css_set_property (css, "stroke", urltext); + + for (GSList const *i = items; i != NULL; i = i->next) { + Inkscape::XML::Node *selrepr = SP_OBJECT_REPR (i->data); + SPObject *selobj = SP_OBJECT (i->data); + if (!selrepr) + continue; + + SPStyle *style = SP_OBJECT_STYLE (selobj); + if (style && style->stroke.isPaintserver()) { + SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER (selobj); + if (SP_IS_PATTERN (server) && pattern_getroot (SP_PATTERN(server)) == pattern) + // only if this object's pattern is not rooted in our selected pattern, apply + continue; + } + + sp_repr_css_change_recursive (selrepr, css, "style"); + } + + sp_repr_css_attr_unref (css); + g_free (urltext); + + } // end if + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Set pattern on stroke")); + } // end if + + break; + + case SP_PAINT_SELECTOR_MODE_UNSET: + if (items) { + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_unset_property (css, "stroke"); + sp_repr_css_unset_property (css, "stroke-opacity"); + sp_repr_css_unset_property (css, "stroke-width"); + sp_repr_css_unset_property (css, "stroke-miterlimit"); + sp_repr_css_unset_property (css, "stroke-linejoin"); + sp_repr_css_unset_property (css, "stroke-linecap"); + sp_repr_css_unset_property (css, "stroke-dashoffset"); + sp_repr_css_unset_property (css, "stroke-dasharray"); + + sp_desktop_set_style (desktop, css); + sp_repr_css_attr_unref (css); + + sp_document_done (document, SP_VERB_DIALOG_FILL_STROKE, + _("Unset stroke")); + } + break; + + default: + g_warning( "file %s: line %d: Paint selector should not be in " + "mode %d", + __FILE__, __LINE__, + psel->mode ); + break; + } + + g_object_set_data (G_OBJECT (spw), "update", GINT_TO_POINTER (FALSE)); +} + + + + + +/* Line */ + +static void sp_stroke_style_line_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data); +static void sp_stroke_style_line_selection_changed(SPWidget *spw, Inkscape::Selection *selection, gpointer data); + +static void sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel); + +static void sp_stroke_style_set_join_buttons(Gtk::Container *spw, Gtk::ToggleButton *active); + +static void sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active); + +static void sp_stroke_style_width_changed(Gtk::Container *spw); +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); + + +/** + * Helper function for creating radio buttons. This should probably be re-thought out + * when reimplementing this with Gtkmm. + */ +static Gtk::RadioButton * +sp_stroke_radio_button(Gtk::RadioButton *tb, char const *icon, + Gtk::HBox *hb, Gtk::Container *spw, + gchar const *key, gchar const *data) +{ + g_assert(icon != NULL); + g_assert(hb != NULL); + g_assert(spw != NULL); + + if (tb == NULL) { + tb = new Gtk::RadioButton(); + } else { + Gtk::RadioButtonGroup grp = tb->get_group(); + tb = new Gtk::RadioButton(grp); + } + + tb->show(); + tb->set_mode(false); + hb->pack_start(*tb, false, false, 0); + spw->set_data(icon, tb); + tb->set_data(key, (gpointer*)data); + tb->signal_toggled().connect(sigc::bind<Gtk::RadioButton *, Gtk::Container *>( + sigc::ptr_fun(&sp_stroke_style_any_toggled), tb, spw)); + Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon))); + g_assert(px != NULL); + px->show(); + tb->add(*px); + + return tb; + +} + +static void +sp_stroke_style_widget_transientize_callback(Inkscape::Application */*inkscape*/, + SPDesktop */*desktop*/, + SPWidget */*spw*/ ) +{ +// TODO: Either of these will cause crashes sometimes +// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); +// ink_markers_menu_update(spw); +} + +/** + * Creates a 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, NRArena const */*arena*/, unsigned /*visionkey*/, NRArenaItem *root) +{ + // 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 = sp_document_repr_doc(sandbox); + Inkscape::XML::Node *mrepr = SP_OBJECT_REPR (marker)->duplicate(xml_doc); + mrepr->setAttribute("id", "sample"); + + // Replace the old sample in the sandbox by the new one + Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (sandbox->getObjectById("defs")); + 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 (sp_document_repr_doc (sandbox), 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); + sp_document_root (sandbox)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + sp_document_ensure_up_to_date(sandbox); + + if (object == NULL || !SP_IS_ITEM(object)) + return NULL; // sandbox broken? + + // Find object's bbox in document + Geom::Matrix const i2doc(sp_item_i2doc_affine(SP_ITEM(object))); + Geom::OptRect dbox = SP_ITEM(object)->getBounds(i2doc); + + 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->uri, 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(root, 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 = (SPDefs *) SP_DOCUMENT_DEFS (source); + for ( SPObject *child = sp_object_first_child(SP_OBJECT(defs)); + child != NULL; + child = SP_OBJECT_NEXT (child) ) + { + 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: + NRArena const *arena = NRArena::create(); + unsigned const visionkey = sp_item_display_key_new(1); + NRArenaItem *root = sp_item_invoke_show(SP_ITEM(SP_DOCUMENT_ROOT (sandbox)), (NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); + + for (; marker_list != NULL; marker_list = marker_list->next) { + Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) marker_list->data); + 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, arena, visionkey, root); + 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); + } + + sp_item_invoke_hide(SP_ITEM(sp_document_root(sandbox)), visionkey); + nr_object_unref((NRObject *) arena); +} + +/** + * sp_marker_list_from_doc() + * + * \brief 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 sp_document_new_from_mem (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 = sp_document_new(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) { + sp_document_ensure_up_to_date(doc); + 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 + * items in the current desktop. + */ +static void +sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const which) +{ + if (spw->get_data("update")) { + return; + } + + SPDesktop *desktop = inkscape_active_desktop(); + SPDocument *document = sp_desktop_document(desktop); + if (!document) { + return; + } + + /* 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 = SP_OBJECT_REPR(mark); + marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); + } + } else { + marker = markid; + } + 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); + + // Also update the marker dropdown menus, so the document's markers + // show up at the top of the menu +// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); + ink_markers_menu_update(spw, which); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = (SPItem *) items->data; + if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) // can't set marker to rect, until it's converted to using <path> + continue; + Inkscape::XML::Node *selrepr = SP_OBJECT_REPR((SPItem *) items->data); + if (selrepr) { + sp_repr_css_change_recursive(selrepr, css, "style"); + } + SP_OBJECT(items->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); + SP_OBJECT(items->data)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } + + sp_repr_css_attr_unref(css); + + sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, + _("Set markers")); + +}; + +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; + + // 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(); + 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(); + 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(); + break; + default: + g_assert_not_reached(); + } +} + +/** + * Sets the stroke width units for all selected items. + * Also handles absolute and dimensionless units. + */ +static gboolean stroke_width_set_unit(SPUnitSelector *, + SPUnit const *old, + SPUnit const *new_units, + Gtk::Container *spw) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + if (!desktop) { + return FALSE; + } + + Inkscape::Selection *selection = sp_desktop_selection (desktop); + + if (selection->isEmpty()) + return FALSE; + + GSList const *objects = selection->itemList(); + + if ((old->base == SP_UNIT_ABSOLUTE || old->base == SP_UNIT_DEVICE) && + (new_units->base == SP_UNIT_DIMENSIONLESS)) { + + /* Absolute to percentage */ + spw->set_data ("update", GUINT_TO_POINTER (TRUE)); + + Gtk::Adjustment *a = static_cast<Gtk::Adjustment *>(spw->get_data("width")); + float w = sp_units_get_pixels (a->get_value(), *old); + + gdouble average = stroke_average_width (objects); + + if (average == NR_HUGE || average == 0) + return FALSE; + + a->set_value (100.0 * w / average); + + spw->set_data ("update", GUINT_TO_POINTER (FALSE)); + return TRUE; + + } else if ((old->base == SP_UNIT_DIMENSIONLESS) && + (new_units->base == SP_UNIT_ABSOLUTE || new_units->base == SP_UNIT_DEVICE)) { + + /* Percentage to absolute */ + spw->set_data ("update", GUINT_TO_POINTER (TRUE)); + + Gtk::Adjustment *a = static_cast<Gtk::Adjustment *>(spw->get_data ("width")); + + gdouble average = stroke_average_width (objects); + + a->set_value (sp_pixels_get_units (0.01 * a->get_value() * average, *new_units)); + + spw->set_data ("update", GUINT_TO_POINTER (FALSE)); + return TRUE; + } + + return FALSE; +} + + +/** + * \brief Creates a new widget for the line stroke style. + * + */ +Gtk::Container * +sp_stroke_style_line_widget_new(void) +{ + Gtk::Widget *us; + SPDashSelector *ds; + GtkWidget *us_old, *spw_old; + Gtk::Container *spw; + Gtk::Table *t; + Gtk::Adjustment *a; + Gtk::SpinButton *sb; + Gtk::RadioButton *tb; + Gtk::HBox *f, *hb; + + Gtk::Tooltips *tt = new Gtk::Tooltips(); + + spw_old = sp_widget_new_global(INKSCAPE); + spw = dynamic_cast<Gtk::Container *>(manage(Glib::wrap(spw_old))); + + f = new Gtk::HBox(false, 0); + f->show(); + spw->add(*f); + + t = new Gtk::Table(3, 6, false); + t->show(); + t->set_border_width(4); + t->set_row_spacings(4); + f->add(*t); + spw->set_data("stroke", t); + + gint i = 0; + + /* Stroke width */ + spw_label(t, Q_("StrokeWidth|Width:"), 0, i); + + hb = spw_hbox(t, 3, 1, i); + +// 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 +// 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. + + a = new Gtk::Adjustment(1.0, 0.0, 1000.0, 0.1, 10.0, 10.0); + spw->set_data("width", a); + sb = new Gtk::SpinButton(*a, 0.1, 3); + tt->set_tip(*sb, _("Stroke width")); + sb->show(); + + sp_dialog_defocus_on_enter_cpp(sb); + + hb->pack_start(*sb, false, false, 0); + us_old = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); + us = manage(Glib::wrap(us_old)); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop) + sp_unit_selector_set_unit (SP_UNIT_SELECTOR(us_old), sp_desktop_namedview(desktop)->doc_units); + sp_unit_selector_add_unit(SP_UNIT_SELECTOR(us_old), &sp_unit_get_by_id(SP_UNIT_PERCENT), 0); + g_signal_connect ( G_OBJECT (us_old), "set_unit", G_CALLBACK (stroke_width_set_unit), spw ); + us->show(); + sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us_old), GTK_ADJUSTMENT(a->gobj()) ); + hb->pack_start(*us, FALSE, FALSE, 0); + spw->set_data("units", us_old); + + a->signal_value_changed().connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_width_changed), spw)); + i++; + + /* Join type */ + // TRANSLATORS: The line join style specifies the shape to be used at the + // corners of paths. It can be "miter", "round" or "bevel". + spw_label(t, _("Join:"), 0, i); + + hb = spw_hbox(t, 3, 1, i); + + tb = NULL; + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_MITER, + hb, spw, "join", "miter"); + + // TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner. + // For an example, draw a triangle with a large stroke width and modify the + // "Join" option (in the Fill and Stroke dialog). + tt->set_tip(*tb, _("Miter join")); + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_ROUND, + hb, spw, "join", "round"); + + // TRANSLATORS: Round join: joining lines with a rounded corner. + // For an example, draw a triangle with a large stroke width and modify the + // "Join" option (in the Fill and Stroke dialog). + tt->set_tip(*tb, _("Round join")); + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_JOIN_BEVEL, + hb, spw, "join", "bevel"); + + // TRANSLATORS: Bevel join: joining lines with a blunted (flattened) corner. + // For an example, draw a triangle with a large stroke width and modify the + // "Join" option (in the Fill and Stroke dialog). + tt->set_tip(*tb, _("Bevel join")); + + i++; + + /* Miterlimit */ + // TRANSLATORS: Miter limit: only for "miter join", this limits the length + // of the sharp "spike" when the lines connect at too sharp an angle. + // When two line segments meet at a sharp angle, a miter join results in a + // spike that extends well beyond the connection point. The purpose of the + // miter limit is to cut off such spikes (i.e. convert them into bevels) + // when they become too long. + spw_label(t, _("Miter limit:"), 0, i); + + hb = spw_hbox(t, 3, 1, i); + + a = new Gtk::Adjustment(4.0, 0.0, 100.0, 0.1, 10.0, 10.0); + spw->set_data("miterlimit", a); + + sb = new Gtk::SpinButton(*a, 0.1, 2); + tt->set_tip(*sb, _("Maximum length of the miter (in units of stroke width)")); + sb->show(); + spw->set_data("miterlimit_sb", sb); + sp_dialog_defocus_on_enter_cpp(sb); + + hb->pack_start(*sb, false, false, 0); + + a->signal_value_changed().connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_miterlimit_changed), spw)); + i++; + + /* Cap type */ + // TRANSLATORS: cap type specifies the shape for the ends of lines + spw_label(t, _("Cap:"), 0, i); + + hb = spw_hbox(t, 3, 1, i); + + tb = NULL; + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_BUTT, + hb, spw, "cap", "butt"); + + // TRANSLATORS: Butt cap: the line shape does not extend beyond the end point + // of the line; the ends of the line are square + tt->set_tip(*tb, _("Butt cap")); + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_ROUND, + hb, spw, "cap", "round"); + + // TRANSLATORS: Round cap: the line shape extends beyond the end point of the + // line; the ends of the line are rounded + tt->set_tip(*tb, _("Round cap")); + + tb = sp_stroke_radio_button(tb, INKSCAPE_ICON_STROKE_CAP_SQUARE, + hb, spw, "cap", "square"); + + // TRANSLATORS: Square cap: the line shape extends beyond the end point of the + // line; the ends of the line are square + tt->set_tip(*tb, _("Square cap")); + + i++; + + + /* Dash */ + spw_label(t, _("Dashes:"), 0, i); + ds = manage(new SPDashSelector); + + ds->show(); + t->attach(*ds, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); + spw->set_data("dash", ds); + ds->changed_signal.connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_line_dash_changed), spw)); + 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); + tt->set_tip(*marker_start_menu, _("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); + + i++; + spw_label(t, _("Mid Markers:"), 0, i); + marker_mid_menu = ink_marker_menu(spw ,"marker-mid", sandbox); + tt->set_tip(*marker_mid_menu, _("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); + + i++; + spw_label(t, _("End Markers:"), 0, i); + marker_end_menu = ink_marker_menu(spw ,"marker-end", sandbox); + tt->set_tip(*marker_end_menu, _("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); + + i++; + + // FIXME: we cheat and still use gtk+ signals + + gtk_signal_connect(GTK_OBJECT(spw_old), "modify_selection", + GTK_SIGNAL_FUNC(sp_stroke_style_line_selection_modified), + spw); + gtk_signal_connect(GTK_OBJECT(spw_old), "change_selection", + GTK_SIGNAL_FUNC(sp_stroke_style_line_selection_changed), + spw); + + sp_stroke_style_line_update(spw, desktop ? sp_desktop_selection(desktop) : NULL); + + return spw; +} + +/** + * Callback for when stroke style widget is modified. + * Triggers update action. + */ +static void +sp_stroke_style_line_selection_modified(SPWidget *, + Inkscape::Selection *selection, + guint flags, + gpointer data) +{ + Gtk::Container *spw = static_cast<Gtk::Container *>(data); + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { + sp_stroke_style_line_update(spw, selection); + } + +} + +/** + * Callback for when stroke style widget is changed. + * Triggers update action. + */ +static void +sp_stroke_style_line_selection_changed(SPWidget *, + Inkscape::Selection *selection, + gpointer data) +{ + Gtk::Container *spw = static_cast<Gtk::Container *>(data); + sp_stroke_style_line_update(spw, selection); +} + +/** + * Sets selector widgets' dash style from an SPStyle object. + */ +static void +sp_dash_selector_set_from_style(SPDashSelector *dsel, SPStyle *style) +{ + if (style->stroke_dash.n_dash > 0) { + double d[64]; + int len = MIN(style->stroke_dash.n_dash, 64); + for (int i = 0; i < len; i++) { + if (style->stroke_width.computed != 0) + d[i] = style->stroke_dash.dash[i] / style->stroke_width.computed; + else + d[i] = style->stroke_dash.dash[i]; // is there a better thing to do for stroke_width==0? + } + dsel->set_dash(len, d, style->stroke_width.computed != 0 ? + style->stroke_dash.offset / style->stroke_width.computed : + style->stroke_dash.offset); + } else { + dsel->set_dash(0, NULL, 0.0); + } +} + +/** + * Sets the join type for a line, and updates the stroke style widget's buttons + */ +static void +sp_jointype_set (Gtk::Container *spw, unsigned const jointype) +{ + Gtk::RadioButton *tb = NULL; + switch (jointype) { + case SP_STROKE_LINEJOIN_MITER: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_MITER)); + break; + case SP_STROKE_LINEJOIN_ROUND: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_ROUND)); + break; + case SP_STROKE_LINEJOIN_BEVEL: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_BEVEL)); + break; + default: + break; + } + sp_stroke_style_set_join_buttons(spw, tb); +} + +/** + * Sets the cap type for a line, and updates the stroke style widget's buttons + */ +static void +sp_captype_set (Gtk::Container *spw, unsigned const captype) +{ + Gtk::RadioButton *tb = NULL; + switch (captype) { + case SP_STROKE_LINECAP_BUTT: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_BUTT)); + break; + case SP_STROKE_LINECAP_ROUND: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_ROUND)); + break; + case SP_STROKE_LINECAP_SQUARE: + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_SQUARE)); + break; + default: + break; + } + sp_stroke_style_set_cap_buttons(spw, tb); +} + +/** + * Callback for when stroke style widget is updated, including markers, cap type, + * join type, etc. + */ +static void +sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) +{ + if (spw->get_data("update")) { + return; + } + + spw->set_data("update", GINT_TO_POINTER(TRUE)); + + Gtk::Table *sset = static_cast<Gtk::Table *>(spw->get_data("stroke")); + Gtk::Adjustment *width = static_cast<Gtk::Adjustment *>(spw->get_data("width")); + Gtk::Adjustment *ml = static_cast<Gtk::Adjustment *>(spw->get_data("miterlimit")); + SPUnitSelector *us = SP_UNIT_SELECTOR(spw->get_data("units")); + SPDashSelector *dsel = static_cast<SPDashSelector *>(spw->get_data("dash")); + + // create temporary style + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + // query into it + int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEWIDTH); + int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT); + int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKECAP); + int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEJOIN); + + if (result_sw == QUERY_STYLE_NOTHING) { + /* No objects stroked, set insensitive */ + sset->set_sensitive(false); + + spw->set_data("update", GINT_TO_POINTER(FALSE)); + return; + } else { + sset->set_sensitive(true); + + SPUnit const *unit = sp_unit_selector_get_unit(us); + + if (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED) { + sp_unit_selector_set_unit(us, &sp_unit_get_by_id(SP_UNIT_PERCENT)); + } else { + // same width, or only one object; no sense to keep percent, switch to absolute + if (unit->base != SP_UNIT_ABSOLUTE && unit->base != SP_UNIT_DEVICE) { + sp_unit_selector_set_unit(us, sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units); + } + } + + unit = sp_unit_selector_get_unit(us); + + if (unit->base == SP_UNIT_ABSOLUTE || unit->base == SP_UNIT_DEVICE) { + double avgwidth = sp_pixels_get_units (query->stroke_width.computed, *unit); + width->set_value(avgwidth); + } else { + width->set_value(100); + } + } + + if (result_ml != QUERY_STYLE_NOTHING) + ml->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness? + + if (result_join != QUERY_STYLE_MULTIPLE_DIFFERENT) { + sp_jointype_set(spw, query->stroke_linejoin.value); + } else { + sp_stroke_style_set_join_buttons(spw, NULL); + } + + if (result_cap != QUERY_STYLE_MULTIPLE_DIFFERENT) { + sp_captype_set (spw, query->stroke_linecap.value); + } else { + sp_stroke_style_set_cap_buttons(spw, NULL); + } + + sp_style_unref(query); + + if (!sel || sel->isEmpty()) + return; + + GSList const *objects = sel->itemList(); + SPObject * const object = SP_OBJECT(objects->data); + SPStyle * const style = SP_OBJECT_STYLE(object); + + /* Markers */ + sp_stroke_style_update_marker_menus(spw, objects); // FIXME: make this desktop query too + + /* Dash */ + sp_dash_selector_set_from_style(dsel, style); // FIXME: make this desktop query too + + sset->set_sensitive(true); + + spw->set_data("update", GINT_TO_POINTER(FALSE)); +} + +/** + * Sets a line's dash properties in a CSS style object. + */ +static void +sp_stroke_style_set_scaled_dash(SPCSSAttr *css, + int ndash, double *dash, double offset, + double scale) +{ + if (ndash > 0) { + Inkscape::CSSOStringStream osarray; + for (int i = 0; i < ndash; i++) { + osarray << dash[i] * scale; + if (i < (ndash - 1)) { + osarray << ","; + } + } + sp_repr_css_set_property(css, "stroke-dasharray", osarray.str().c_str()); + + Inkscape::CSSOStringStream osoffset; + osoffset << offset * scale; + sp_repr_css_set_property(css, "stroke-dashoffset", osoffset.str().c_str()); + } else { + sp_repr_css_set_property(css, "stroke-dasharray", "none"); + sp_repr_css_set_property(css, "stroke-dashoffset", NULL); + } +} + +/** + * Sets line properties like width, dashes, markers, etc. on all currently selected items. + */ +static void +sp_stroke_style_scale_line(Gtk::Container *spw) +{ + if (spw->get_data("update")) { + return; + } + + spw->set_data("update", GINT_TO_POINTER(TRUE)); + + Gtk::Adjustment *wadj = static_cast<Gtk::Adjustment *>(spw->get_data("width")); + SPUnitSelector *us = SP_UNIT_SELECTOR(spw->get_data("units")); + SPDashSelector *dsel = static_cast<SPDashSelector *>(spw->get_data("dash")); + Gtk::Adjustment *ml = static_cast<Gtk::Adjustment *>(spw->get_data("miterlimit")); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *document = sp_desktop_document (desktop); + Inkscape::Selection *selection = sp_desktop_selection (desktop); + + GSList const *items = selection->itemList(); + + /* TODO: Create some standardized method */ + SPCSSAttr *css = sp_repr_css_attr_new(); + + if (items) { + + double width_typed = wadj->get_value(); + double const miterlimit = ml->get_value(); + + SPUnit const *const unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us)); + + double *dash, offset; + int ndash; + dsel->get_dash(&ndash, &dash, &offset); + + for (GSList const *i = items; i != NULL; i = i->next) { + /* Set stroke width */ + double width; + if (unit->base == SP_UNIT_ABSOLUTE || unit->base == SP_UNIT_DEVICE) { + width = sp_units_get_pixels (width_typed, *unit); + } else { // percentage + gdouble old_w = SP_OBJECT_STYLE (i->data)->stroke_width.computed; + width = old_w * width_typed / 100; + } + + { + Inkscape::CSSOStringStream os_width; + os_width << width; + sp_repr_css_set_property(css, "stroke-width", os_width.str().c_str()); + } + + { + Inkscape::CSSOStringStream os_ml; + os_ml << miterlimit; + sp_repr_css_set_property(css, "stroke-miterlimit", os_ml.str().c_str()); + } + + /* Set dash */ + sp_stroke_style_set_scaled_dash(css, ndash, dash, offset, width); + + sp_desktop_apply_css_recursive (SP_OBJECT(i->data), css, true); + } + + g_free(dash); + + if (unit->base != SP_UNIT_ABSOLUTE && unit->base != SP_UNIT_DEVICE) { + // reset to 100 percent + wadj->set_value(100.0); + } + + } + + // we have already changed the items, so set style without changing selection + // FIXME: move the above stroke-setting stuff, including percentages, to desktop-style + sp_desktop_set_style (desktop, css, false); + + sp_repr_css_attr_unref(css); + + sp_document_done(document, SP_VERB_DIALOG_FILL_STROKE, + _("Set stroke style")); + + spw->set_data("update", GINT_TO_POINTER(FALSE)); +} + +/** + * Callback for when the stroke style's width changes. + * Causes all line styles to be applied to all selected items. + */ +static void +sp_stroke_style_width_changed(Gtk::Container *spw) +{ + if (spw->get_data("update")) { + return; + } + + sp_stroke_style_scale_line(spw); +} + +/** + * Callback for when the stroke style's miterlimit changes. + * Causes all line styles to be applied to all selected items. + */ +static void +sp_stroke_style_miterlimit_changed(Gtk::Container *spw) +{ + if (spw->get_data("update")) { + return; + } + + sp_stroke_style_scale_line(spw); +} + +/** + * Callback for when the stroke style's dash changes. + * Causes all line styles to be applied to all selected items. + */ + +static void +sp_stroke_style_line_dash_changed(Gtk::Container *spw) +{ + if (spw->get_data("update")) { + return; + } + + sp_stroke_style_scale_line(spw); +} + +/** + * \brief This routine handles toggle events for buttons in the stroke style + * dialog. + * When activated, this routine gets the data for the various widgets, and then + * calls the respective routines to update css properties, etc. + * + */ +static void +sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *spw) +{ + if (spw->get_data("update")) { + return; + } + + if (tb->get_active()) { + + gchar const *join + = static_cast<gchar const *>(tb->get_data("join")); + gchar const *cap + = static_cast<gchar const *>(tb->get_data("cap")); + + if (join) { + Gtk::SpinButton *ml = static_cast<Gtk::SpinButton *>(spw->get_data("miterlimit_sb")); + ml->set_sensitive(!strcmp(join, "miter")); + } + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + /* TODO: Create some standardized method */ + SPCSSAttr *css = sp_repr_css_attr_new(); + + if (join) { + sp_repr_css_set_property(css, "stroke-linejoin", join); + + sp_desktop_set_style (desktop, css); + + sp_stroke_style_set_join_buttons(spw, tb); + } else if (cap) { + sp_repr_css_set_property(css, "stroke-linecap", cap); + + sp_desktop_set_style (desktop, css); + + sp_stroke_style_set_cap_buttons(spw, tb); + } + + sp_repr_css_attr_unref(css); + + sp_document_done(sp_desktop_document(desktop), SP_VERB_DIALOG_FILL_STROKE, + _("Set stroke style")); + } +} + +/** + * Updates the join style toggle buttons + */ +static void +sp_stroke_style_set_join_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) +{ + Gtk::RadioButton *tb; + + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_MITER)); + tb->set_active(active == tb); + + Gtk::SpinButton *ml = static_cast<Gtk::SpinButton *>(spw->get_data("miterlimit_sb")); + ml->set_sensitive(active == tb); + + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_ROUND)); + tb->set_active(active == tb); + + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_JOIN_BEVEL)); + tb->set_active(active == tb); +} + +/** + * Updates the cap style toggle buttons + */ +static void +sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) +{ + Gtk::RadioButton *tb; + + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_BUTT)); + tb->set_active(active == tb); + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_ROUND)); + tb->set_active(active == tb); + tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON_STROKE_CAP_SQUARE)); + 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 (SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")) + mark_is_stock = true; + + gchar *markname; + if (mark_is_stock) + markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")); + else + markname = g_strdup(SP_OBJECT_REPR(marker)->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 + * that marker. + */ +static void +sp_stroke_style_update_marker_menus(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 } + }; + + bool all_texts = true; + for (GSList *i = (GSList *) objects; i != NULL; i = i->next) { + if (!SP_IS_TEXT (i->data)) { + all_texts = false; + } + } + + 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); + } + + // We show markers of the first object in the list only + // FIXME: use the first in the list that has the marker of each type, if any + SPObject *object = SP_OBJECT(objects->data); + + 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)); + + // Quit if we're in update state + if (mnu->get_data("update")) { + return; + } + + if (object->style->marker[keyloc[i].loc].value != NULL && !all_texts) { + // If the object has this type of markers, + + // Extract the name of the marker that the object uses + SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, SP_OBJECT_DOCUMENT(object)); + // Scroll the menu to that marker + ink_marker_menu_set_current(marker, mnu); + + } else { + mnu->set_history(0); + } + } +} + + +/** + * Extract the actual name of the link + * e.g. get mTriangle from url(#mTriangle). + * \return Buffer containing the actual name, allocated from GLib; + * the caller should free the buffer when they no longer need it. + */ +static SPObject* +ink_extract_marker_name(gchar const *n, SPDocument *doc) +{ + gchar const *p = n; + while (*p != '\0' && *p != '#') { + p++; + } + + if (*p == '\0' || p[1] == '\0') { + return NULL; + } + + p++; + int c = 0; + while (p[c] != '\0' && p[c] != ')') { + c++; + } + + if (p[c] == '\0') { + return NULL; + } + + gchar* b = g_strdup(p); + b[c] = '\0'; + + // FIXME: get the document from the object and let the caller pass it in + SPObject *marker = doc->getObjectById(b); + return marker; +} + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h new file mode 100644 index 000000000..b947209e3 --- /dev/null +++ b/src/widgets/stroke-style.h @@ -0,0 +1,35 @@ +/** @file + * @brief Stroke style dialog + */ +/* Author: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 2001 Ximian, Inc. + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_DIALOGS_STROKE_STYLE_H +#define SEEN_DIALOGS_STROKE_STYLE_H + +#include <glib.h> + +#include <gtk/gtkwidget.h> + +#include "forward.h" +#include "display/canvas-bpath.h" + +GtkWidget *sp_stroke_style_paint_widget_new (void); +Gtk::Container *sp_stroke_style_line_widget_new (void); + +#endif + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 14acb188a..e3dcbcc14 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -36,7 +36,6 @@ #include "../box3d-context.h" #include "../box3d.h" -#include "calligraphic-profile-rename.h" #include "../conn-avoid-ref.h" #include "../connection-pool.h" #include "../connector-context.h" @@ -87,6 +86,7 @@ #include "../svg/css-ostringstream.h" #include "../tools-switch.h" #include "../tweak-context.h" +#include "../ui/dialog/calligraphic-profile-rename.h" #include "../ui/icon-names.h" #include "../ui/widget/style-swatch.h" #include "../verbs.h"